adding missing tests around Sandbox's CLI module (#668)

* introducing CliSpec

* updating sandbox sdk docs

* fixing the missing code block

* adding missing copyright headers

* making allow-dev hidden

* HardCoded -> Predefined

* updated changelog
This commit is contained in:
Gabor Aranyossy 2019-04-26 10:12:23 +02:00 committed by GitHub
parent 80e2107130
commit cc32ee5025
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 160 additions and 39 deletions

View File

@ -30,6 +30,8 @@ HEAD — ongoing
implement "callable updates" (aka functions of type ``Update a`` that can be
called from the Ledger API via a contract).
- Publish the participant-state APIs and reference implementations.
- Add `-s` option to Sandbox CLI to have a shortened version for `--static-time` as well
- Change `--allow-dev` to be a hidden CLI option in Sandbox
0.12.7 — 2019-04-17
-------------------

View File

@ -29,18 +29,20 @@ Here, ``da run sandbox --`` tells the SDK Assistant to run ``sandbox`` from the
Command-line reference
**********************
Sandbox requires the names of the input ``.dar`` or ``.dalf`` files as arguments to start.
The available command line options are listed here::
-p, --port <value> Sandbox service port. Defaults to 6865.
-a, --address <value> Sandbox service host. Defaults to binding on all addresses.
--dalf This argument is present for backwards compatibility. DALF and DAR archives are now identified by their extensions.
--static-time Use static time, configured with TimeService through gRPC.
-w, --wall-clock-time Use wall clock time (UTC). When not provided, static time is used.
--no-parity Disables Ledger Server parity mode. Features which are not supported by the Platform become available.
--scenario <value> If set, the sandbox will execute the given scenario on startup and store all the contracts created by it. Two formats are supported: Module.Name:Entity.Name (preferred) and Module.Name.Entity.Name (deprecated, will print a warning when used).
--daml-lf-archive-recursion-limit <value>
Set the recursion limit when decoding DAML-LF archives (.dalf files). Default is 1000
<archive>... Daml archives to load. Either in .dar or .dalf format. Only DAML-LF v1 Archives are currently supported.
--help Print the usage text
::
Usage: sandbox [options] <archive>...
-p, --port <value> Sandbox service port. Defaults to 6865.
-a, --address <value> Sandbox service host. Defaults to binding on all addresses.
--dalf This argument is present for backwards compatibility. DALF and DAR archives are now identified by their extensions.
-s, --static-time Use static time, configured with TimeService through gRPC.
-w, --wall-clock-time Use wall clock time (UTC). When not provided, static time is used.
--no-parity Legacy flag with no effect.
--scenario <value> If set, the sandbox will execute the given scenario on startup and store all the contracts created by it. Two formats are supported: Module.Name:Entity.Name (preferred) and Module.Name.Entity.Name (deprecated, will print a warning when used).
<archive>... Daml archives to load. Either in .dar or .dalf format. Only DAML-LF v1 Archives are currently supported.
--pem <value> TLS: The pem file to be used as the private key.
--crt <value> TLS: The crt file to be used as the cert chain. Required if any other TLS parameters are set.
--cacrt <value> TLS: The crt file to be used as the the trusted root CA.
--ledgerid <value> Sandbox ledger ID. If missing, a random unique ledger ID will be used. Only useful with persistent stores.
--help Print the usage text

View File

@ -51,7 +51,7 @@ class CodegenLedgerTest extends FlatSpec with Matchers {
val cfg = SandboxConfig.default.copy(
port = 0,
damlPackageContainer = DamlPackageContainer(List(testDalf)),
ledgerIdMode = LedgerIdMode.HardCoded(LedgerID),
ledgerIdMode = LedgerIdMode.Predefined(LedgerID),
timeProviderType = TimeProviderType.WallClock,
timeModel = TimeModel.reasonableDefault
)

View File

@ -101,7 +101,7 @@ class ScalaCodeGenIT
port = port,
damlPackageContainer = DamlPackageContainer(archives),
timeProviderType = TimeProviderType.WallClock,
ledgerIdMode = LedgerIdMode.HardCoded(ledgerId),
ledgerIdMode = LedgerIdMode.Predefined(ledgerId),
)
private val sandbox: SandboxServer = SandboxApplication(serverConfig)

View File

@ -51,7 +51,7 @@ object ExampleMain extends App {
port = port,
damlPackageContainer = DamlPackageContainer(List(dar)),
timeProviderType = TimeProviderType.WallClock,
ledgerIdMode = LedgerIdMode.HardCoded(ledgerId),
ledgerIdMode = LedgerIdMode.Predefined(ledgerId),
)
private val server: SandboxServer = SandboxApplication(serverConfig)

View File

@ -102,7 +102,7 @@ object PlatformApplications {
SandboxApplication(
SandboxConfig(
addressOption = None,
address = None,
port = selectedPort,
damlPackageContainer = DamlPackageContainer(config.darFiles.map(_.toFile)),
timeProviderType = config.timeProviderType,
@ -111,7 +111,7 @@ object PlatformApplications {
scenario = None,
tlsConfig = None,
ledgerIdMode =
config.ledgerId.fold[LedgerIdMode](LedgerIdMode.Random)(LedgerIdMode.HardCoded),
config.ledgerId.fold[LedgerIdMode](LedgerIdMode.Random)(LedgerIdMode.Predefined),
jdbcUrl = jdbcUrl
)
)

View File

@ -139,7 +139,7 @@ object Application {
new Server(
"LedgerApiServer",
config.addressOption,
config.address,
config.port,
config,
serverSslContext(config.tlsConfig, ClientAuth.REQUIRE),

View File

@ -57,7 +57,7 @@ object LedgerApiServer {
services(config, ledgerBackend, engine, timeProvider, optTimeServiceBackend)(mat, esf)
},
optResetService,
config.addressOption,
config.address,
serverPort,
serverSslContext(config.tlsConfig, ClientAuth.REQUIRE)
).start()

View File

@ -165,7 +165,7 @@ object SandboxApplication {
new SandboxServer(
"sandbox",
config.addressOption,
config.address,
config.port,
config,
serverSslContext(config.tlsConfig, ClientAuth.REQUIRE),

View File

@ -8,7 +8,7 @@ import java.time.Duration
import com.digitalasset.ledger.client.configuration.TlsConfiguration
import com.digitalasset.platform.sandbox.BuildInfo
import com.digitalasset.platform.sandbox.config.LedgerIdMode.HardCoded
import com.digitalasset.platform.sandbox.config.LedgerIdMode.Predefined
import com.digitalasset.platform.sandbox.config.SandboxConfig
import com.digitalasset.platform.services.time.TimeProviderType
import scopt.Read
@ -25,12 +25,7 @@ object Cli {
override val reads: String => Duration = Duration.parse
}
private val crtConfig = (path: String, config: SandboxConfig) =>
config.copy(
tlsConfig =
config.tlsConfig.fold(Some(TlsConfiguration(true, Some(new File(path)), None, None)))(c =>
Some(c.copy(keyCertChainFile = Some(new File(path))))))
// format: off
private val cmdArgParser = new scopt.OptionParser[SandboxConfig]("sandbox") {
head(s"Sandbox version ${BuildInfo.Version}")
@ -39,7 +34,7 @@ object Cli {
.text(s"Sandbox service port. Defaults to ${SandboxConfig.DefaultPort}.")
opt[String]('a', "address")
.action((x, c) => c.copy(addressOption = Some(x)))
.action((x, c) => c.copy(address = Some(x)))
.text("Sandbox service host. Defaults to binding on all addresses.")
// TODO remove in next major release.
@ -48,7 +43,7 @@ object Cli {
.text(
"This argument is present for backwards compatibility. DALF and DAR archives are now identified by their extensions.")
opt[Unit]("static-time")
opt[Unit]('s', "static-time")
.action { (_, c) =>
assertTimeModeIsDefault(c)
c.copy(timeProviderType = TimeProviderType.Static)
@ -91,7 +86,11 @@ object Cli {
opt[String]("crt")
.optional()
.text("TLS: The crt file to be used as the cert chain. Required if any other TLS parameters are set.")
.action(crtConfig)
.action((path: String, config: SandboxConfig) =>
config.copy(
tlsConfig =
config.tlsConfig.fold(Some(TlsConfiguration(true, Some(new File(path)), None, None)))(c =>
Some(c.copy(keyCertChainFile = Some(new File(path)))))))
opt[String]("cacrt")
.optional()
@ -108,6 +107,7 @@ object Cli {
.action((url, config) => config.copy(jdbcUrl = Some(url)))
opt[Unit]("allow-dev")
.hidden()
.action { (_, c) =>
c.copy(damlPackageContainer = c.damlPackageContainer.allowDev)
}
@ -116,12 +116,12 @@ object Cli {
//TODO (robert): Think about all implications of allowing users to set the ledger ID.
opt[String]("ledgerid")
.optional()
.action((id, c) => c.copy(ledgerIdMode = HardCoded(id)))
.action((id, c) => c.copy(ledgerIdMode = Predefined(id)))
.text("Sandbox ledger ID. If missing, a random unique ledger ID will be used. Only useful with persistent stores.")
help("help").text("Print the usage text")
}
// format: on
private def assertTimeModeIsDefault(c: SandboxConfig): Unit = {
if (c.timeProviderType != TimeProviderType.default)
throw new IllegalArgumentException(

View File

@ -61,9 +61,9 @@ case class DamlPackageContainer(files: List[File] = Nil, devAllowed: Boolean = f
lazy val packageIds: Iterable[String] = archives.map(_.getHash)
def withFile(file: File): DamlPackageContainer = DamlPackageContainer(file :: files)
def withFile(file: File): DamlPackageContainer = copy(files = file :: files)
def getPackage(id: PackageId): Option[Ast.Package] = packages.get(id)
def allowDev: DamlPackageContainer = DamlPackageContainer(files, true)
def allowDev: DamlPackageContainer = copy(devAllowed = true)
}

View File

@ -11,7 +11,7 @@ sealed trait LedgerIdMode extends Product with Serializable {
object LedgerIdMode {
final case class HardCoded(_ledgerId: String) extends LedgerIdMode {
final case class Predefined(_ledgerId: String) extends LedgerIdMode {
def ledgerId(): String = _ledgerId
}

View File

@ -20,7 +20,7 @@ final case class TlsServerConfiguration(
* Defines the basic configuration for running sandbox
*/
final case class SandboxConfig(
addressOption: Option[String],
address: Option[String],
port: Int,
damlPackageContainer: DamlPackageContainer,
timeProviderType: TimeProviderType,

View File

@ -0,0 +1,117 @@
// Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.digitalasset.platform.sandbox.cli
import java.io.File
import com.digitalasset.ledger.client.configuration.TlsConfiguration
import com.digitalasset.platform.sandbox.config.LedgerIdMode.Predefined
import com.digitalasset.platform.sandbox.config.SandboxConfig
import com.digitalasset.platform.services.time.TimeProviderType
import org.scalatest.{Matchers, WordSpec}
class CliSpec extends WordSpec with Matchers {
private val archiveName = "whatever.dar"
private val defaultConfig = SandboxConfig.default
private def checkOption(
options: Array[String],
expectedChange: SandboxConfig => SandboxConfig) = {
val expectedConfig = expectedChange(
defaultConfig.copy(
damlPackageContainer = defaultConfig.damlPackageContainer.withFile(new File(archiveName))))
val config =
Cli.parse(options ++: Array(archiveName))
config shouldEqual Some(expectedConfig)
}
"Cli" should {
"return None when required arguments are missing" in {
val config = Cli.parse(Array.empty)
config shouldEqual None
}
"return a Config with sensible defaults when mandatory arguments are given" in {
val expectedConfig = defaultConfig.copy(
damlPackageContainer = defaultConfig.damlPackageContainer.withFile(new File(archiveName)))
val config = Cli.parse(Array(archiveName))
config shouldEqual Some(expectedConfig)
}
"parse the port when given" in {
val port = "1234"
checkOption(Array(s"-p", port), _.copy(port = port.toInt))
checkOption(Array(s"--port", port), _.copy(port = port.toInt))
}
"parse the address when given" in {
val address = "myhost"
checkOption(Array(s"-a", address), _.copy(address = Some(address)))
checkOption(Array(s"--address", address), _.copy(address = Some(address)))
}
"apply static time when given" in {
checkOption(Array(s"-s"), _.copy(timeProviderType = TimeProviderType.Static))
checkOption(Array(s"--static-time"), _.copy(timeProviderType = TimeProviderType.Static))
}
"apply wall-clock time when given" in {
checkOption(
Array(s"--wall-clock-time"),
_.copy(timeProviderType = TimeProviderType.WallClock))
checkOption(Array(s"-w"), _.copy(timeProviderType = TimeProviderType.WallClock))
}
"parse the scenario when given" in {
val scenario = "myscenario"
checkOption(Array(s"--scenario", scenario), _.copy(scenario = Some(scenario)))
}
"parse the crt file when given" in {
val crt = "mycrt"
checkOption(
Array(s"--crt", crt),
_.copy(tlsConfig = Some(TlsConfiguration(true, Some(new File(crt)), None, None))))
}
"parse the cacrt file when given" in {
val cacrt = "mycacrt"
checkOption(
Array(s"--cacrt", cacrt),
_.copy(tlsConfig = Some(TlsConfiguration(true, None, None, Some(new File(cacrt))))))
}
"parse the pem file when given" in {
val pem = "mypem"
checkOption(
Array(s"--pem", pem),
_.copy(tlsConfig = Some(TlsConfiguration(true, None, Some(new File(pem)), None))))
}
"enable allow-dev when given" in {
checkOption(
Array(s"--allow-dev"),
c => c.copy(damlPackageContainer = c.damlPackageContainer.allowDev))
}
"parse the ledger id when given" in {
val ledgerId = "myledger"
checkOption(Array(s"--ledgerid", ledgerId), _.copy(ledgerIdMode = Predefined(ledgerId)))
}
"parse the jdbc url when given" in {
val jdbcUrl = "jdbc:postgresql://localhost:5432/test?user=test"
checkOption(Array(s"--jdbcurl", jdbcUrl), _.copy(jdbcUrl = Some(jdbcUrl)))
}
}
}

View File

@ -54,7 +54,7 @@ trait SandboxFixture extends SuiteResource[Channel] {
timeProviderType = TimeProviderType.Static,
timeModel = TimeModel.reasonableDefault,
scenario = scenario,
ledgerIdMode = LedgerIdMode.HardCoded("sandbox server")
ledgerIdMode = LedgerIdMode.Predefined("sandbox server")
)
protected def packageFiles: List[File] = List(darFile)