diff --git a/docs/source/daml-integration-kit/index.rst b/docs/source/daml-integration-kit/index.rst index 30897e6849..36a1f7127e 100644 --- a/docs/source/daml-integration-kit/index.rst +++ b/docs/source/daml-integration-kit/index.rst @@ -397,17 +397,17 @@ implementation of the :doc:`Ledger API `. For example, it will show you if there are consistency or conformance problem with your implementation. -Assuming that your Ledger API endpoint is accessible at ``localhost:6864``, you can use the tool in the following manner: +Assuming that your Ledger API endpoint is accessible at ``localhost:6865``, you can use the tool in the following manner: #. Obtain the tool: ``curl -L 'https://bintray.com/api/v1/content/digitalassetsdk/DigitalAssetSDK/com/daml/ledger/testtool/ledger-api-test-tool_2.12/$latest/ledger-api-test-tool_2.12-$latest.jar?bt_package=sdk-components' -o ledger-api-test-tool.jar`` -#. Obtain the DAML archive required to run the tests: +#. Obtain the DAML archives required to run the tests: ``java -jar ledger-api-test-tool.jar --extract`` -#. Load ``SemanticTests.dar`` which was created in the current directory into your Ledger. +#. Load all ``.dar`` files extracted in the current directory into your Ledger. #. Run the tool against your ledger: diff --git a/docs/source/support/release-notes.rst b/docs/source/support/release-notes.rst index aa168f5821..521b7c4237 100644 --- a/docs/source/support/release-notes.rst +++ b/docs/source/support/release-notes.rst @@ -58,6 +58,17 @@ Sandbox - Added recovery around failing ledger entry persistence queries using Postgres. See `#1505 `__. +DAML Integration Kit +~~~~~~~~~~~~~~~~~~~~ + +- The :doc:`Ledger API Test Tool ` can now optionally run ``TransactionServiceIT`` as part of the conformance tests. + This means you need to load additional ``.dar`` files into the ledger under test. Please refer to the updated instructions in the :doc:`documentation `. +- Added new CLI options to the :doc:`Ledger API Test Tool `: + + - ``--list`` prints all available tests to the console + - ``--include`` takes a comma-separated list of test names that should be run + - ``--exclude`` takes a comma-separated list of test names that should not be run + 0.12.22 - 2019-05-29 -------------------- diff --git a/docs/source/tools/ledger-api-test-tool/index.rst b/docs/source/tools/ledger-api-test-tool/index.rst index b1cf19779a..9bda0efc2f 100644 --- a/docs/source/tools/ledger-api-test-tool/index.rst +++ b/docs/source/tools/ledger-api-test-tool/index.rst @@ -35,21 +35,21 @@ Run the following command to fetch the tool: This will create a file ``ledger-api-test-tool.jar`` in your current directory. -Extracting ``.dar`` file required to run the tests +Extracting ``.dar`` files required to run the tests ====================================================== Before you can run the Ledger API test tool on your ledger, you need to load a specific set of DAML templates onto your ledger. -#. To obtain the corresponding ``.dar`` file, run: +#. To obtain the corresponding ``.dar`` files, run: .. code-block:: console $ java -jar ledger-api-test-tool.jar --extract - This creates a file ``SemanticTests.dar`` in the current directory. + This writes all ``.dar`` files required for the tests into the current directory. -#. Load ``SemanticTests.dar`` into your Ledger. +#. Load all ``.dar`` files into your Ledger. Running the tool against a custom Ledger API endpoint ===================================================== @@ -79,7 +79,22 @@ Run the tool with ``--help`` flag to obtain the list of options the tool provide $ java -jar ledger-api-test-tool.jar --help -| +Filtering tests +~~~~~~~~~~~~~~~ + +You can list the available tests with the ``--list`` flag. Some tests are not run by default. You can run them with the ``--include`` flag. To exclude tests, use the ``--exclude`` flag. + +This command only runs the test ``TestA``: + +.. code-block:: console + + $ java -jar ledger-api-test-tool.jar --include TestA + +This command runs all tests except the test ``TestB``: + +.. code-block:: console + + $ java -jar ledger-api-test-tool.jar --exclude TestB Try out the Ledger API Test Tool against DAML Sandbox ===================================================== @@ -90,7 +105,7 @@ If you wanted to test out the tool, you can run it against :doc:`DAML Sandbox .. code-block:: console $ java -jar ledger-api-test-tool.jar --extract - $ da sandbox -- SemanticTests.dar + $ da sandbox -- *.dar $ java -jar ledger-api-test-tool.jar This should always succeed, as the Sandbox is tested to correctly implement the diff --git a/ledger-api/testing-utils/src/main/scala/com/digitalasset/ledger/api/testing/utils/AkkaBeforeAndAfterAll.scala b/ledger-api/testing-utils/src/main/scala/com/digitalasset/ledger/api/testing/utils/AkkaBeforeAndAfterAll.scala index 91e43cd93f..b0ab093080 100644 --- a/ledger-api/testing-utils/src/main/scala/com/digitalasset/ledger/api/testing/utils/AkkaBeforeAndAfterAll.scala +++ b/ledger-api/testing-utils/src/main/scala/com/digitalasset/ledger/api/testing/utils/AkkaBeforeAndAfterAll.scala @@ -19,7 +19,7 @@ trait AkkaBeforeAndAfterAll extends BeforeAndAfterAll { protected def actorSystemName = this.getClass.getSimpleName private val logger = LoggerFactory.getLogger(getClass) - private val executorContext = ExecutionContext.fromExecutorService( + private lazy val executorContext = ExecutionContext.fromExecutorService( Executors.newSingleThreadExecutor( new ThreadFactoryBuilder() .setDaemon(true) @@ -28,10 +28,10 @@ trait AkkaBeforeAndAfterAll extends BeforeAndAfterAll { logger.error(s"got an uncaught exception on thread: ${thread.getName}")) .build())) - protected implicit val system: ActorSystem = + protected implicit lazy val system: ActorSystem = ActorSystem(actorSystemName, defaultExecutionContext = Some(executorContext)) - protected implicit val materializer: ActorMaterializer = ActorMaterializer() + protected implicit lazy val materializer: ActorMaterializer = ActorMaterializer() override protected def afterAll(): Unit = { materializer.shutdown() diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/ActiveContractsServiceIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/ActiveContractsServiceIT.scala index 3cd25a9027..d5230eb614 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/ActiveContractsServiceIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/ActiveContractsServiceIT.scala @@ -27,7 +27,6 @@ import org.scalatest.concurrent.{AsyncTimeLimitedTests, ScalaFutures} import org.scalatest.time.SpanSugar._ import org.scalatest.time.{Millis, Span} import org.scalatest.{Assertion, AsyncWordSpec, Matchers, OptionValues} - import scalaz.syntax.tag._ /** @@ -46,11 +45,13 @@ class ActiveContractsServiceIT with ScalaFutures with AsyncTimeLimitedTests with Matchers - with OptionValues - with TestCommands { + with OptionValues { override def timeLimit: Span = 60.seconds + protected val testCommands = new TestCommands(config) + protected val templateIds = testCommands.templateIds + override implicit def patienceConfig: PatienceConfig = PatienceConfig(scaled(Span(30000, Millis)), scaled(Span(500, Millis))) @@ -97,7 +98,7 @@ class ActiveContractsServiceIT }.size should equal(occurrence) def threeCommands(ledgerId: domain.LedgerId, commandId: String): SubmitAndWaitRequest = - super.dummyCommands(ledgerId, commandId, "Alice").toWait + testCommands.toWait(testCommands.dummyCommands(ledgerId, commandId, "Alice")) private def filter = TransactionFilter(Map(config.parties.head -> Filters())) @@ -190,11 +191,13 @@ class ActiveContractsServiceIT contractId = extractContractId(responses1) _ <- submitRequest( ctx, - buildRequest( - ctx.ledgerId, - "exercise-test-exercised", - Seq(exerciseWithUnit(templateIds.dummy, contractId, "DummyChoice1")), - "Alice").toWait) + testCommands.toWait( + testCommands.buildRequest( + ctx.ledgerId, + "exercise-test-exercised", + Seq(testCommands.exerciseWithUnit(templateIds.dummy, contractId, "DummyChoice1")), + "Alice")) + ) responses2 <- waitForActiveContracts( ctx.acsService, ctx.ledgerId, @@ -223,11 +226,12 @@ class ActiveContractsServiceIT val resultsF = for { _ <- submitRequest( ctx, - buildRequest( - ctx.ledgerId, - "commandId1", - Seq(createWithOperator(templateIds.dummy, "Alice")), - "Alice").toWait) + testCommands.toWait( + testCommands.buildRequest( + ctx.ledgerId, + "commandId1", + Seq(testCommands.createWithOperator(templateIds.dummy, "Alice")), + "Alice"))) responses1 <- waitForActiveContracts( ctx.acsService, ctx.ledgerId, @@ -236,11 +240,12 @@ class ActiveContractsServiceIT offset = extractOffset(responses1) _ <- submitRequest( ctx, - buildRequest( - ctx.ledgerId, - "commandId2", - Seq(createWithOperator(templateIds.dummyWithParam, "Alice")), - "Alice").toWait + testCommands.toWait( + testCommands.buildRequest( + ctx.ledgerId, + "commandId2", + Seq(testCommands.createWithOperator(templateIds.dummyWithParam, "Alice")), + "Alice")) ) responses2 <- transactionClient(ctx) .getTransactions( @@ -283,8 +288,12 @@ class ActiveContractsServiceIT "multi-party request comes" should { "return the correct set of related contracts" in allFixtures { ctx => val resultsF = for { - _ <- submitRequest(ctx, dummyCommands(ctx.ledgerId, "acsCommand-1", "Alice").toWait) - _ <- submitRequest(ctx, dummyCommands(ctx.ledgerId, "acsCommand-2", "Bob").toWait) + _ <- submitRequest( + ctx, + testCommands.toWait(testCommands.dummyCommands(ctx.ledgerId, "acsCommand-1", "Alice"))) + _ <- submitRequest( + ctx, + testCommands.toWait(testCommands.dummyCommands(ctx.ledgerId, "acsCommand-2", "Bob"))) allContractsForAlice <- waitForActiveContracts( ctx.acsService, ctx.ledgerId, diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/DivulgenceIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/DivulgenceIT.scala index 8e0b390917..8978781aaf 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/DivulgenceIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/DivulgenceIT.scala @@ -45,10 +45,12 @@ class DivulgenceIT with ScalaFutures with AsyncTimeLimitedTests with Matchers - with OptionValues - with TestTemplateIds { + with OptionValues { override protected def config: Config = Config.default + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds + private implicit def party(s: String): Ref.Party = Ref.Party.assertFromString(s) private implicit def pkgId(s: String): Ref.PackageId = Ref.PackageId.assertFromString(s) private implicit def id(s: String): Ref.Name = Ref.Name.assertFromString(s) diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/LotsOfPartiesIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/LotsOfPartiesIT.scala index dc09b6e371..271b02b67b 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/LotsOfPartiesIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/LotsOfPartiesIT.scala @@ -27,8 +27,10 @@ class LotsOfPartiesIT with MultiLedgerFixture with SuiteResourceManagementAroundAll with AsyncTimeLimitedTests - with Matchers - with TestTemplateIds { + with Matchers { + + protected lazy val testTemplateIds = new TestTemplateIds(config) + protected lazy val templateIds = testTemplateIds.templateIds private val numParties = 1024 private val allParties: List[String] = diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceIT.scala index b3be2583b8..1eb55e72ea 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceIT.scala @@ -8,8 +8,10 @@ import java.time.{Duration, Instant} import akka.Done import akka.stream.scaladsl.{Flow, Sink} import com.digitalasset.daml.lf.data.Ref +import com.digitalasset.daml.lf.data.Ref.QualifiedName +import com.digitalasset.daml.lf.types.Ledger import com.digitalasset.grpc.adapter.utils.DirectExecutionContext -import com.digitalasset.ledger.api.domain.EventId +import com.digitalasset.ledger.api.domain.{EventId, LedgerId} import com.digitalasset.ledger.api.testing.utils.MockMessages.{party, _} import com.digitalasset.ledger.api.testing.utils.{ AkkaBeforeAndAfterAll, @@ -17,6 +19,7 @@ import com.digitalasset.ledger.api.testing.utils.{ MockMessages, SuiteResourceManagementAroundAll } +import com.digitalasset.ledger.api.v1.command_service.SubmitAndWaitRequest import com.digitalasset.ledger.api.v1.commands.Command.Command.Create import com.digitalasset.ledger.api.v1.commands.{Command, CreateCommand, ExerciseCommand} import com.digitalasset.ledger.api.v1.event.Event.Event.{Archived, Created} @@ -35,6 +38,7 @@ import com.digitalasset.ledger.api.v1.value.{ Value, Variant } +import com.digitalasset.ledger.client.services.commands.CommandUpdater import com.digitalasset.ledger.client.services.transactions.TransactionClient import com.digitalasset.platform.api.v1.event.EventOps._ import com.digitalasset.platform.apitesting.LedgerContextExtensions._ @@ -53,8 +57,7 @@ import scalaz.{ICons, NonEmptyList, Tag} import scala.collection.{breakOut, immutable} import scala.concurrent.Future - -import com.digitalasset.ledger.api.domain.LedgerId +import scala.util.Random @SuppressWarnings(Array("org.wartremover.warts.Any")) class TransactionServiceIT @@ -65,15 +68,25 @@ class TransactionServiceIT with Inside with AsyncTimeLimitedTests with TestExecutionSequencerFactory - with TransactionServiceHelpers with ParameterShowcaseTesting with OptionValues - with Matchers - with TestTemplateIds { + with Matchers { - override protected val config: Config = + override protected def config: Config = Config.default.withTimeProvider(TimeProviderType.WallClock) + protected val helpers = new TransactionServiceHelpers(config) + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds + + val runSuffix = "-" + Random.alphanumeric.take(10).mkString + val partyNameMangler = + (partyText: String) => partyText + runSuffix + Random.alphanumeric.take(10).mkString + val commandIdMangler: ((QualifiedName, Int, Ledger.ScenarioNodeId) => String) = + (testName, stepId, nodeId) => { + s"ledger-api-test-tool-$testName-$stepId-$nodeId-$runSuffix" + } + override val timeLimit: Span = 300.seconds private def newClient(stub: TransactionService, ledgerId: LedgerId): TransactionClient = @@ -118,7 +131,11 @@ class TransactionServiceIT val elemsToTake = 10L for { - _ <- insertCommands(getTrackerFlow(context), "cancellation-test", 14, context.ledgerId) + _ <- insertCommandsUnique( + "cancellation-test", + 14, + context + ) transactions <- context.transactionClient .getTransactions(ledgerBegin, None, getAllContracts) .take(elemsToTake) @@ -133,8 +150,8 @@ class TransactionServiceIT val client = context.transactionClient for { le <- client.getLedgerEnd - _ <- insertCommands("deduplicated", 1, context) - _ = insertCommands("deduplicated", 1, context) // we don't wait for this since the result won't be seen + _ <- insertCommandsUnique("deduplicated", 1, context) + _ = insertCommandsUnique("deduplicated", 1, context) // we don't wait for this since the result won't be seen txs <- client .getTransactions(le.getOffset, None, getAllContracts) .takeWithin(2.seconds) @@ -161,11 +178,7 @@ class TransactionServiceIT .runWith(Sink.seq) for { - _ <- insertCommands( - getTrackerFlow(context), - "stream-completion-test", - 14, - context.ledgerId) + _ <- insertCommandsUnique("stream-completion-test", 14, context) _ <- resultsF } yield { succeed // resultF would not complete unless the server terminates the connection @@ -182,7 +195,7 @@ class TransactionServiceIT for { ledgerEndResponse <- client.getLedgerEnd - _ <- insertCommands(firstSectionPrefix, commandsPerSection, context) + _ <- insertCommandsUnique(firstSectionPrefix, commandsPerSection, context) firstSection <- client .getTransactions(ledgerEndResponse.getOffset, None, getAllContracts) .filter(_.commandId.startsWith(sharedPrefix)) @@ -191,7 +204,7 @@ class TransactionServiceIT _ = firstSection should have size commandsPerSection.toLong ledgerEndAfterFirstSection = lastOffsetIn(firstSection).value - _ <- insertCommands(sharedPrefix + "-2", commandsPerSection, context) + _ <- insertCommandsUnique(sharedPrefix + "-2", commandsPerSection, context) secondSection <- client .getTransactions(ledgerEndAfterFirstSection, None, getAllContracts) @@ -223,7 +236,7 @@ class TransactionServiceIT for { ledgerEndOnStart <- client.getLedgerEnd - _ <- insertCommands(commandPrefix, smallCommandCount, context) + _ <- insertCommandsUnique(commandPrefix, smallCommandCount, context) readTransactions = () => client .getTransactions(ledgerEndOnStart.getOffset, None, getAllContracts) @@ -251,7 +264,7 @@ class TransactionServiceIT val anotherParty = "Alice" for { ledgerEndResponse <- client.getLedgerEnd - _ <- insertCommands(commandPrefix, 1, context) + _ <- insertCommandsUnique(commandPrefix, 1, context) // At this point we verified that the value has been written to the submitter's LSM. // This test code assumes that the value would be written to other parties' LSMs within 100 ms. transactions <- client @@ -299,7 +312,7 @@ class TransactionServiceIT for { savedLedgerEnd <- client.getLedgerEnd - _ <- insertCommands("end-before-start-test", 1, context) + _ <- insertCommandsUnique(s"end-before-start-test", 1, context) tx <- client .getTransactions(savedLedgerEnd.getOffset, None, getAllContracts) .runWith(Sink.head) @@ -319,7 +332,7 @@ class TransactionServiceIT "expose transactions to non-submitting stakeholders without the commandId" in allFixtures { c => c.submitCreateAndReturnTransaction( - "Checking_commandId_visibility_for_non-submitter_party", + s"Checking_commandId_visibility_for_non-submitter_party-${runSuffix}", templateIds.agreementFactory, List("receiver" -> party1.asParty, "giver" -> party2.asParty).asRecordFields, party2, @@ -330,7 +343,7 @@ class TransactionServiceIT } "expose only the requested templates to the client" in allFixtures { context => - val commandId = "Client_should_see_only_the_Dummy_create." + val commandId = s"Client_should_see_only_the_Dummy_create-${runSuffix}" val templateInSubscription = templateIds.dummy val otherTemplateCreated = templateIds.dummyFactory for { @@ -353,8 +366,8 @@ class TransactionServiceIT "expose contract Ids that are ready to be used for exercising choices" in allFixtures { context => - val factoryCreation = "Creating_factory" - val exercisingChoice = "Exercising_choice_on_factory" + val factoryCreation = s"Creating_factory-${runSuffix}" + val exercisingChoice = s"Exercising_choice_on_factory-${runSuffix}" val exercisedTemplate = templateIds.dummyFactory for { createdEvent <- context.submitCreate( @@ -379,8 +392,8 @@ class TransactionServiceIT "expose contract Ids that are results of exercising choices when filtering by template" in allFixtures { context => - val factoryCreation = "Creating_second_factory" - val exercisingChoice = "Exercising_choice_on_second_factory" + val factoryCreation = s"Creating_second_factory-${runSuffix}" + val exercisingChoice = s"Exercising_choice_on_second_factory-${runSuffix}" val exercisedTemplate = templateIds.dummyFactory for { creation <- context.submitCreate( @@ -423,7 +436,7 @@ class TransactionServiceIT "reject exercising a choice where an assertion fails" in allFixtures { c => for { dummy <- c.submitCreate( - "Create_for_assertion_failing_test", + s"Create_for_assertion_failing_test-${runSuffix}", templateIds.dummy, List("operator" -> party.asParty).asRecordFields, party) @@ -452,7 +465,7 @@ class TransactionServiceIT val expectedArg = paramShowcaseArgsWithoutLabels for { create <- c.submitCreate( - "Creating_contract_with_a_multitude_of_param_types", + s"Creating_contract_with_a_multitude_of_param_types-${runSuffix}", template, paramShowcaseArgs(templateIds.testPackageId), "party", @@ -470,7 +483,7 @@ class TransactionServiceIT val variant = Value(Value.Sum.Variant(Variant(None, "SomeInteger", 1.asInt64))) for { create <- c.submitCreate( - "Creating_contract_with_a_multitude_of_verbose_param_types", + s"Creating_contract_with_a_multitude_of_verbose_param_types-${runSuffix}", template, arg, "party", @@ -523,7 +536,7 @@ class TransactionServiceIT val template = templateIds.parameterShowcase for { create <- c.submitCreate( - "Huge_command_with_a_long_list", + s"Huge_command_with_a_long_list-${runSuffix}", template, arg, "party" @@ -538,15 +551,16 @@ class TransactionServiceIT val giver = "Alice" for { created <- c.submitCreateWithListenerAndReturnEvent( - "Creating_Agreement_Factory", + s"Creating_Agreement_Factory-${runSuffix}", templateIds.agreementFactory, List("receiver" -> receiver.asParty, "giver" -> giver.asParty).asRecordFields, giver, - giver) + giver + ) choiceResult <- c.testingHelpers.submitAndListenForSingleResultOfCommand( c.command( - "Calling_non-consuming_choice", + s"Calling_non-consuming_choice-${runSuffix}", List( ExerciseCommand( Some(templateIds.agreementFactory), @@ -572,7 +586,7 @@ class TransactionServiceIT for { branchingSignatories <- c.submitCreateWithListenerAndReturnEvent( - "BranchingSignatoriesTrue", + s"BranchingSignatoriesTrue-${runSuffix}", templateIds.branchingSignatories, branchingSignatoriesArg, party1, @@ -586,7 +600,7 @@ class TransactionServiceIT val branchingSignatoriesArg = getBranchingSignatoriesArg(false, party1, party2) c.submitCreateWithListenerAndAssertNotVisible( - "BranchingSignatoriesFalse", + s"BranchingSignatoriesFalse-${runSuffix}", templateIds.branchingSignatories, branchingSignatoriesArg, party2, @@ -599,7 +613,7 @@ class TransactionServiceIT val expectedArg = branchingControllersArgs.map(_.copy(label = "")) for { branchingControllers <- c.submitCreateWithListenerAndReturnEvent( - "BranchingControllersTrue", + s"BranchingControllersTrue-${runSuffix}", templateId, branchingControllersArgs, party1, @@ -614,7 +628,7 @@ class TransactionServiceIT val branchingControllersArgs = getBranchingControllerArgs(party1, party2, party3, false) c.submitCreateWithListenerAndAssertNotVisible( - "BranchingControllersFalse", + s"BranchingControllersFalse-${runSuffix}", templateId, branchingControllersArgs, party1, @@ -634,7 +648,7 @@ class TransactionServiceIT .sequence(observers.map(observer => for { withObservers <- c.submitCreateWithListenerAndReturnEvent( - "Obs1create:" + observer, + s"Obs1create:${observer}-${runSuffix}", templateIds.withObservers, withObserversArg, giver, @@ -655,7 +669,7 @@ class TransactionServiceIT val expectedArgs = createArguments.map(_.copy(label = "")) c.submitCreate( - "Creating_contract_with_a_Nothing_argument", + s"Creating_contract_with_a_Nothing_argument-${runSuffix}", templateIds.nothingArgument, createArguments, "party") @@ -673,7 +687,7 @@ class TransactionServiceIT "expose the default agreement text in CreatedEvents for templates with no explicit agreement text" in allFixtures { c => val resultF = c.submitCreate( - "Creating_dummy_contract_for_default_agreement_text_test", + s"Creating_dummy_contract_for_default_agreement_text_test-${runSuffix}", templateIds.dummy, List(RecordField("operator", party1.asParty)), party1) @@ -690,12 +704,12 @@ class TransactionServiceIT for { agreement <- createAgreement(c, "MA1", receiver, giver) triProposal <- c.submitCreate( - "MA1proposal", + s"MA1proposal-${runSuffix}", templateIds.triProposal, triProposalArg, operator) tx <- c.submitExercise( - "MA1acceptance", + s"MA1acceptance-${runSuffix}", templateIds.agreement, List("cid" -> Value(ContractId(triProposal.contractId))).asRecordValue, "AcceptTriProposal", @@ -716,12 +730,12 @@ class TransactionServiceIT val expectedArg = triProposalArg.map(_.copy(label = "")) for { triProposal <- c.submitCreate( - "MA2proposal", + s"MA2proposal-${runSuffix}", templateIds.triProposal, triProposalArg, operator) tx <- c.submitExercise( - "MA2acceptance", + s"MA2acceptance-${runSuffix}", templateIds.triProposal, unitArg, "TriProposalAccept", @@ -738,7 +752,7 @@ class TransactionServiceIT val triProposalArg = mkTriProposalArg(operator, receiver, giver) for { triProposal <- c.submitCreate( - "MA3proposal", + s"MA3proposal-${runSuffix}", templateIds.triProposal, triProposalArg, operator) @@ -769,7 +783,7 @@ class TransactionServiceIT for { agreement <- createAgreement(c, "MA4", receiver, giver) triProposal <- c.submitCreate( - "MA4proposal", + s"MA4proposal-${runSuffix}", templateIds.triProposal, triProposalArg, operator) @@ -794,12 +808,12 @@ class TransactionServiceIT val arguments = List("street", "city", "state", "zip") for { dummy <- c.submitCreate( - "Create_dummy_for_creating_AddressWrapper", + s"Create_dummy_for_creating_AddressWrapper-${runSuffix}", templateIds.dummy, List("operator" -> party.asParty).asRecordFields, party) exercise <- c.submitExercise( - "Creating_AddressWrapper", + s"Creating_AddressWrapper-${runSuffix}", templateIds.dummy, List("address" -> arguments.map(e => e -> e.asText).asRecordValue).asRecordValue, "WrapWithAddress", @@ -860,13 +874,13 @@ class TransactionServiceIT val createAndFetchTid = templateIds.createAndFetch for { createdEvent <- context.submitCreate( - "CreateAndFetch_Create", + s"CreateAndFetch_Create-$runSuffix", createAndFetchTid, List("p" -> party.asParty).asRecordFields, party) cid = createdEvent.contractId exerciseTx <- context.submitExercise( - "CreateAndFetch_Run", + s"CreateAndFetch_Run-$runSuffix", createAndFetchTid, Value(Value.Sum.Record(Record())), "CreateAndFetch_Run", @@ -916,11 +930,7 @@ class TransactionServiceIT val beginOffset = LedgerOffset(LedgerOffset.Value.Boundary(LedgerOffset.LedgerBoundary.LEDGER_BEGIN)) for { - _ <- insertCommands( - getTrackerFlow(context), - "tree-provenance-by-id", - 1, - context.ledgerId) + _ <- insertCommandsUnique("tree-provenance-by-id", 1, context) firstTransaction <- context.transactionClient .getTransactions(beginOffset, None, transactionFilter) .runWith(Sink.head) @@ -1015,11 +1025,7 @@ class TransactionServiceIT val beginOffset = LedgerOffset(LedgerOffset.Value.Boundary(LedgerOffset.LedgerBoundary.LEDGER_BEGIN)) for { - _ <- insertCommands( - getTrackerFlow(context), - "flat-provenance-by-id", - 1, - context.ledgerId) + _ <- insertCommandsUnique("flat-provenance-by-id", 1, context) firstTransaction <- context.transactionClient .getTransactions(beginOffset, None, transactionFilter) .runWith(Sink.head) @@ -1085,11 +1091,7 @@ class TransactionServiceIT val beginOffset = LedgerOffset(LedgerOffset.Value.Boundary(LedgerOffset.LedgerBoundary.LEDGER_BEGIN)) for { - _ <- insertCommands( - getTrackerFlow(context), - "tree-provenance-by-event-id", - 1, - context.ledgerId) + _ <- insertCommandsUnique("tree-provenance-by-event-id", 1, context) tx <- context.transactionClient .getTransactions(beginOffset, None, transactionFilter) .runWith(Sink.head) @@ -1154,11 +1156,7 @@ class TransactionServiceIT val beginOffset = LedgerOffset(LedgerOffset.Value.Boundary(LedgerOffset.LedgerBoundary.LEDGER_BEGIN)) for { - _ <- insertCommands( - getTrackerFlow(context), - "flat-provenance-by-event-id", - 1, - context.ledgerId) + _ <- insertCommandsUnique("flat-provenance-by-event-id", 1, context) tx <- context.transactionClient .getTransactions(beginOffset, None, transactionFilter) .runWith(Sink.head) @@ -1305,11 +1303,7 @@ class TransactionServiceIT .runWith(Sink.seq) for { - _ <- insertCommands( - getTrackerFlow(context), - "cancellation-test-tree", - commandsToSend, - context.ledgerId) + _ <- insertCommandsUnique("cancellation-test-tree", commandsToSend, context) elems <- resultsF } yield (elems should have length elemsToTake) } @@ -1368,11 +1362,7 @@ class TransactionServiceIT r1 <- context.transactionClient .getTransactionTrees(ledgerBegin, Some(ledgerEnd), transactionFilter) .runWith(Sink.seq) - _ <- insertCommands( - getTrackerFlow(context), - "complete_test", - noOfCommands, - context.ledgerId) + _ <- insertCommandsUnique("complete_test", noOfCommands, context) r2 <- context.transactionClient .getTransactionTrees(ledgerBegin, Some(ledgerEnd), transactionFilter) .runWith(Sink.seq) @@ -1509,7 +1499,27 @@ class TransactionServiceIT prefix: String, commandsPerSection: Int, context: LedgerContext): Future[Done] = { - insertCommands(getTrackerFlow(context), prefix, commandsPerSection, context.ledgerId) + helpers.insertCommands( + request => applyTimeAndSubmit(request, context), + prefix, + commandsPerSection, + context.ledgerId) + } + + private def applyTimeAndSubmit(req: SubmitAndWaitRequest, context: LedgerContext) = { + context.commandClient().flatMap { client => + val ttl = Duration.ofMillis(config.commandConfiguration.commandTtl.toMillis) + val updater = new CommandUpdater(client.timeProviderO, ttl, true) + val reqToSend = req.copy(commands = req.commands.map(updater.applyOverrides)) + context.commandService.submitAndWaitForTransactionId(reqToSend) + } + } + + private def insertCommandsUnique( + prefix: String, + commandsPerSection: Int, + context: LedgerContext): Future[Done] = { + insertCommands(s"${prefix}-${runSuffix}", commandsPerSection, context) } private def lastOffsetIn(secondSection: immutable.Seq[Transaction]): Option[LedgerOffset] = { @@ -1600,15 +1610,16 @@ class TransactionServiceIT ): Future[CreatedEvent] = { for { agreementFactory <- c.submitCreate( - commandId + "factory_creation", + commandId + s"factory_creation-${runSuffix}", templateIds.agreementFactory, List( "receiver" -> receiver.asParty, "giver" -> giver.asParty ).asRecordFields, - giver) + giver + ) tx <- c.submitExercise( - commandId + "_acceptance", + commandId + s"_acceptance-${runSuffix}", templateIds.agreementFactory, unitArg, "AgreementFactoryAccept", @@ -1632,7 +1643,7 @@ class TransactionServiceIT ): Future[Assertion] = c.testingHelpers.assertCommandFailsWithCode( c.command( - commandId, + s"${commandId}-${runSuffix}", List(ExerciseCommand(Some(template), contractId, choice, Some(arg)).wrap)) .update( _.commands.party := submitter @@ -1650,7 +1661,7 @@ class TransactionServiceIT for { creation <- context.submitCreate( - s"Creating_contract_with_a_multitude_of_param_types_for_exercising_$choice#$lbl", + s"Creating_contract_with_a_multitude_of_param_types_for_exercising-${runSuffix}_$choice#$lbl", templateIds.parameterShowcase, paramShowcaseArgs(templateIds.testPackageId), MockMessages.party @@ -1664,7 +1675,9 @@ class TransactionServiceIT exerciseArg).wrap exerciseTx <- context.testingHelpers.submitAndListenForSingleResultOfCommand( context - .command(s"Exercising_with_a_multitiude_of_params_$choice#$lbl", List(exerciseCommand)), + .command( + s"Exercising_with_a_multitiude_of_params-${runSuffix}_$choice#$lbl", + List(exerciseCommand)), getAllContracts ) } yield { diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceLargeCommandIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceLargeCommandIT.scala index 42148a33df..e544d5d848 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceLargeCommandIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceLargeCommandIT.scala @@ -33,15 +33,17 @@ class TransactionServiceLargeCommandIT with Inside with AsyncTimeLimitedTests with TestExecutionSequencerFactory - with TransactionServiceHelpers with ParameterShowcaseTesting with OptionValues - with Matchers - with TestTemplateIds { + with Matchers { override protected val config: Config = Config.default.withTimeProvider(TimeProviderType.Static) + protected val helpers = new TransactionServiceHelpers(config) + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds + override val timeLimit: Span = 300.seconds private val getAllContracts = transactionFilter diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WitnessesIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WitnessesIT.scala index 674b675eca..184bd904b5 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WitnessesIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WitnessesIT.scala @@ -29,10 +29,12 @@ class WitnessesIT with SuiteResourceManagementAroundEach with ScalaFutures with AsyncTimeLimitedTests - with Matchers - with TestTemplateIds { + with Matchers { override protected def config: Config = Config.default + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds + private def commandClient(ctx: LedgerContext): SynchronousCommandClient = new SynchronousCommandClient(ctx.commandService) diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WronglyTypedContractIdIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WronglyTypedContractIdIT.scala index 5e7a6b4c9c..5faa656be3 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WronglyTypedContractIdIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/WronglyTypedContractIdIT.scala @@ -22,10 +22,12 @@ class WronglyTypedContractIdIT with SuiteResourceManagementAroundEach with ScalaFutures with AsyncTimeLimitedTests - with Matchers - with TestTemplateIds { + with Matchers { override protected def config: Config = Config.default + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds + def createDummy(ctx: LedgerContext) = ctx.testingHelpers.simpleCreate( "create-dummy", "alice", diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandClientIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandClientIT.scala index fbb20933f0..0d98e4b6df 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandClientIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandClientIT.scala @@ -46,8 +46,10 @@ class CommandClientIT with SuiteResourceManagementAroundAll with ParameterShowcaseTesting with TryValues - with MultiLedgerCommandUtils - with TestTemplateIds { + with MultiLedgerCommandUtils { + + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds private val submittingParty: String = submitRequest.getCommands.party private val submittingPartyList = List(submittingParty) diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandStaticTimeIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandStaticTimeIT.scala index 679abc140e..3c970829a0 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandStaticTimeIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/CommandStaticTimeIT.scala @@ -46,9 +46,11 @@ class CommandStaticTimeIT with ScalaFutures with SuiteResourceManagementAroundAll with MultiLedgerCommandUtils - with TestTemplateIds with OptionValues { + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds + override def timeLimit: Span = 15.seconds private val tenDays: time.Duration = java.time.Duration.ofDays(10L) diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/FailingCommandsIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/FailingCommandsIT.scala index bedcee7b8d..da4058f4d7 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/FailingCommandsIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/FailingCommandsIT.scala @@ -78,7 +78,7 @@ class FailingCommandsIT .runWith(Sink.head) } yield { result.value should matchPattern { - case Completion(`failingCommandId`, Some(status), _, _) if status.code == 3 => + case Completion(helpers.failingCommandId, Some(status), _, _) if status.code == 3 => } } } diff --git a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/transaction/TransactionBackpressureIT.scala b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/transaction/TransactionBackpressureIT.scala index b0c3d74942..6e82eb5fe2 100644 --- a/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/transaction/TransactionBackpressureIT.scala +++ b/ledger/ledger-api-integration-tests/src/test/itsuite/scala/com/digitalasset/platform/tests/integration/ledger/api/transaction/TransactionBackpressureIT.scala @@ -35,8 +35,9 @@ class TransactionBackpressureIT with ScalaFutures with AkkaBeforeAndAfterAll with SuiteResourceManagementAroundAll - with MultiLedgerFixture - with TestCommands { + with MultiLedgerFixture { + + protected val testCommands = new TestCommands(config) override def timeLimit: Span = 300.seconds @@ -63,7 +64,8 @@ class TransactionBackpressureIT Source(1 to noOfCommands) .throttle(10, 1.second) .mapAsync(10)(i => - commandClient.submitSingleCommand(oneKbCommandRequest(ctx.ledgerId, s"command-$i"))) + commandClient.submitSingleCommand( + testCommands.oneKbCommandRequest(ctx.ledgerId, s"command-$i"))) .runWith(Sink.ignore) def subscribe(rate: Int) = diff --git a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/CommandTransactionChecks.scala b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/CommandTransactionChecks.scala index 340d29892b..487cd62e62 100644 --- a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/CommandTransactionChecks.scala +++ b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/CommandTransactionChecks.scala @@ -60,11 +60,13 @@ abstract class CommandTransactionChecks with ScalaFutures with AsyncTimeLimitedTests with Matchers - with OptionValues - with TestTemplateIds { + with OptionValues { protected def submitCommand(ctx: LedgerContext, req: SubmitRequest): Future[Completion] - override protected val config: Config = Config.default + protected val testTemplateIds = new TestTemplateIds(config) + protected val templateIds = testTemplateIds.templateIds + + override protected def config: Config = Config.default private lazy val dummyTemplates = List(templateIds.dummy, templateIds.dummyFactory, templateIds.dummyWithParam) diff --git a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/TestCommands.scala b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/TestCommands.scala index 090ab1144b..e9d17a49a1 100644 --- a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/TestCommands.scala +++ b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/apitesting/TestCommands.scala @@ -3,8 +3,10 @@ package com.digitalasset.platform.apitesting +import java.io.File import java.util +import com.digitalasset.daml.lf.UniversalArchiveReader import com.digitalasset.ledger.api.domain import com.digitalasset.ledger.api.testing.utils.MockMessages.{ applicationId, @@ -19,19 +21,22 @@ import com.digitalasset.ledger.api.v1.commands.{Command, CreateCommand, Exercise import com.digitalasset.ledger.api.v1.value.Value.Sum import com.digitalasset.ledger.api.v1.value.Value.Sum.{Party, Text} import com.digitalasset.ledger.api.v1.value.{Identifier, Record, RecordField, Value} -import com.digitalasset.platform.tests.integration.ledger.api.TransactionServiceHelpers +import com.digitalasset.platform.PlatformApplications import com.google.protobuf.timestamp.Timestamp - import scalaz.syntax.tag._ -trait TestTemplateIds extends TransactionServiceHelpers { - protected lazy val templateIds: TestTemplateIdentifiers = { - new TestTemplateIdentifiers(parsedPackageId) - } +class TestTemplateIds(config: PlatformApplications.Config) { + lazy val defaultDar: File = config.darFiles.head.toFile + lazy val parsedPackageId: String = + UniversalArchiveReader().readFile(defaultDar).get.main._1 + lazy val templateIds: TestTemplateIdentifiers = new TestTemplateIdentifiers(parsedPackageId) } -trait TestCommands extends TestTemplateIds { - protected def buildRequest( +class TestCommands(config: PlatformApplications.Config) { + protected val testIds = new TestTemplateIds(config) + val templateIds = testIds.templateIds + + def buildRequest( ledgerId: domain.LedgerId, commandId: String, commands: Seq[Command], @@ -49,10 +54,7 @@ trait TestCommands extends TestTemplateIds { _.commands.maximumRecordTime := maxRecordTime ) - protected def dummyCommands( - ledgerId: domain.LedgerId, - commandId: String, - party: String = "party") = + def dummyCommands(ledgerId: domain.LedgerId, commandId: String, party: String = "party") = buildRequest( ledgerId, commandId, @@ -64,7 +66,7 @@ trait TestCommands extends TestTemplateIds { party ) - protected def createWithOperator(templateId: Identifier, party: String = "party") = + def createWithOperator(templateId: Identifier, party: String = "party") = Command( Create(CreateCommand( Some(templateId), @@ -77,7 +79,7 @@ trait TestCommands extends TestTemplateIds { new String(array) } - protected def oneKbCommand(templateId: Identifier) = + def oneKbCommand(templateId: Identifier) = Command( Create( CreateCommand( @@ -91,21 +93,19 @@ trait TestCommands extends TestTemplateIds { ))) ))) - protected def oneKbCommandRequest( + def oneKbCommandRequest( ledgerId: domain.LedgerId, commandId: String, party: String = "party"): SubmitRequest = buildRequest(ledgerId, commandId, List(oneKbCommand(templateIds.textContainer)), party) - protected def exerciseWithUnit( + def exerciseWithUnit( templateId: Identifier, contractId: String, choice: String, args: Option[Value] = Some(Value(Sum.Record(Record.defaultInstance)))) = Command(Exercise(ExerciseCommand(Some(templateId), contractId, choice, args))) - implicit class SubmitRequestEnhancer(request: SubmitRequest) { - def toWait: SubmitAndWaitRequest = SubmitAndWaitRequest(request.commands) - } + def toWait(request: SubmitRequest): SubmitAndWaitRequest = SubmitAndWaitRequest(request.commands) } diff --git a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/LedgerTestingHelpers.scala b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/LedgerTestingHelpers.scala index 0be72efa59..300746152e 100644 --- a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/LedgerTestingHelpers.scala +++ b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/LedgerTestingHelpers.scala @@ -27,8 +27,8 @@ import com.google.rpc.status.Status import io.grpc.StatusRuntimeException import org.scalatest.concurrent.Waiters import org.scalatest.{Assertion, Inside, Matchers, OptionValues} - import scalaz.syntax.tag._ + import scala.collection.{breakOut, immutable} import scala.concurrent.duration._ import scala.concurrent.{ExecutionContext, ExecutionContextExecutor, Future} diff --git a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceHelpers.scala b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceHelpers.scala index 263e67515d..4decc9033e 100644 --- a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceHelpers.scala +++ b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/TransactionServiceHelpers.scala @@ -7,25 +7,26 @@ import java.io.File import akka.Done import akka.stream.Materializer -import akka.stream.scaladsl.{Flow, Sink, Source} +import akka.stream.scaladsl.{Sink, Source} import com.digitalasset.daml.lf.UniversalArchiveReader import com.digitalasset.ledger.api.domain -import com.digitalasset.ledger.api.testing.utils.MockMessages.submitRequest -import com.digitalasset.ledger.api.v1.command_submission_service.SubmitRequest +import com.digitalasset.ledger.api.testing.utils.MockMessages.submitAndWaitRequest +import com.digitalasset.ledger.api.v1.command_service.{ + SubmitAndWaitForTransactionIdResponse, + SubmitAndWaitRequest +} import com.digitalasset.ledger.api.v1.commands.Command.Command.Create import com.digitalasset.ledger.api.v1.commands.{Command, CreateCommand} -import com.digitalasset.ledger.api.v1.completion.Completion import com.digitalasset.ledger.api.v1.value.Value.Sum import com.digitalasset.ledger.api.v1.value.{Identifier, Record, RecordField, Value} import com.digitalasset.platform.PlatformApplications -import com.digitalasset.util.Ctx import org.scalatest.Matchers - import scalaz.syntax.tag._ + import scala.concurrent.Future -trait TransactionServiceHelpers extends Matchers { - lazy val defaultDar: File = PlatformApplications.Config.defaultDarFile +class TransactionServiceHelpers(config: PlatformApplications.Config) extends Matchers { + lazy val defaultDar: File = config.darFiles.head.toFile lazy val parsedPackageId: String = UniversalArchiveReader().readFile(defaultDar).get.main._1 @@ -47,15 +48,15 @@ trait TransactionServiceHelpers extends Matchers { .withTemplateId(dummyTemplate) .withCreateArguments(wrongArgs)) - def submitRequestWithId(id: String, command: Command, ledgerId: domain.LedgerId) = - submitRequest + def submitAndWaitRequestWithId(id: String, command: Command, ledgerId: domain.LedgerId) = + submitAndWaitRequest .update(_.commands.commandId := id) .update(_.commands.commands := Seq(command)) .update(_.commands.ledgerId := ledgerId.unwrap) // TODO command tracking should be used here def insertCommands( - trackingFlow: Flow[Ctx[Int, SubmitRequest], Ctx[Int, Completion], _], + submit: SubmitAndWaitRequest => Future[SubmitAndWaitForTransactionIdResponse], prefix: String, i: Int, ledgerId: domain.LedgerId, @@ -63,15 +64,11 @@ trait TransactionServiceHelpers extends Matchers { val arg = Record(Some(dummyTemplate), Vector(RecordField("operator", Some(Value(Sum.Party(party)))))) val command = Create(CreateCommand(Some(dummyTemplate), Some(arg))) - Source(for { - x <- Range(0, i) - req = submitRequestWithId(s"$prefix-$x", Command(command), ledgerId) - c = Ctx(x, req) - } yield c) - .via(trackingFlow) + Source(Range(0, i)) + .map(x => submitAndWaitRequestWithId(s"$prefix-$x", Command(command), ledgerId)) + .mapAsync(1)(submit) .runWith(Sink.foreach { - case Ctx(i, Completion(_, Some(status), transactionId, _)) => - status should have('code (0)) + case SubmitAndWaitForTransactionIdResponse(transactionId) => transactionId should not be empty () }) diff --git a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/MultiLedgerCommandUtils.scala b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/MultiLedgerCommandUtils.scala index 674c412336..79f1b5ece2 100644 --- a/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/MultiLedgerCommandUtils.scala +++ b/ledger/ledger-api-integration-tests/src/test/lib/scala/com/digitalasset/platform/tests/integration/ledger/api/commands/MultiLedgerCommandUtils.scala @@ -21,12 +21,14 @@ import scalaz.syntax.tag._ Array( "org.wartremover.warts.Any" )) -trait MultiLedgerCommandUtils extends TransactionServiceHelpers with MultiLedgerFixture { +trait MultiLedgerCommandUtils extends MultiLedgerFixture { self: AsyncTestSuite => protected final def newSynchronousCommandClient(ctx: LedgerContext): SynchronousCommandClient = new SynchronousCommandClient(ctx.commandService) + protected val helpers = new TransactionServiceHelpers(config) + protected val testLedgerId = domain.LedgerId("ledgerId") protected val testNotLedgerId = domain.LedgerId("hotdog") protected val submitRequest: SubmitRequest = @@ -38,10 +40,10 @@ trait MultiLedgerCommandUtils extends TransactionServiceHelpers with MultiLedger Commands() .withParty("Alice") .withLedgerId(testLedgerId.unwrap) - .withCommandId(failingCommandId) + .withCommandId(helpers.failingCommandId) .withWorkflowId(workflowId) .withApplicationId(applicationId) - .withCommands(Seq(wrongCreate)))) + .withCommands(Seq(helpers.wrongCreate)))) protected val submitAndWaitRequest: SubmitAndWaitRequest = MockMessages.submitAndWaitRequest diff --git a/ledger/ledger-api-test-tool/BUILD.bazel b/ledger/ledger-api-test-tool/BUILD.bazel index dcb78748f4..57fa701ce9 100644 --- a/ledger/ledger-api-test-tool/BUILD.bazel +++ b/ledger/ledger-api-test-tool/BUILD.bazel @@ -64,6 +64,7 @@ da_scala_binary( resources = [ "src/main/resources/logback.xml", "//ledger/ledger-api-integration-tests:SemanticTests.dar", + "//ledger/sandbox:Test.dar", ], tags = [ "maven_coordinates=com.daml.ledger.testtool:ledger-api-test-tool:__VERSION__", diff --git a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Cli.scala b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Cli.scala index f2f7acffba..d65e922755 100644 --- a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Cli.scala +++ b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Cli.scala @@ -64,6 +64,10 @@ object Cli { |Defaults to 1.0. Use numbers higher than 1.0 to make test timeouts more lax, |use numbers lower than 1.0 to make test timeouts more strict.""".stripMargin) + opt[Unit]("verbose") + .action((_, c) => c.copy(verbose = true)) + .text("Prints full stacktraces on failures.") + opt[Unit]("must-fail") .action((_, c) => c.copy(mustFail = true)) .text("""Reverse success status logic of the tool. Use this flag if you expect one or @@ -76,6 +80,19 @@ object Cli { .text("""Extract a DAR necessary to test a DAML ledger and exit without running tests. |The DAR needs to be manually loaded into a DAML ledger for the tool to work.""".stripMargin) + opt[Seq[String]]("exclude") + .action((ex, c) => c.copy(excluded = ex.toSet)) + .text("""A comma-separated list of tests that should NOT be run. By default, no tests are excluded.""") + + opt[Seq[String]]("include") + .action((inc, c) => c.copy(included = inc.toSet)) + .text( + """A comma-separated list of tests that should be run. By default, all tests are run.""") + + opt[Unit]("list") + .action((_, c) => c.copy(listTests = true)) + .text("""Lists all available tests that can be used in the include and exclude options.""") + } def parse(args: Array[String]): Option[Config] = diff --git a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Config.scala b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Config.scala index 74aa41cbec..2ffb5e6ffe 100644 --- a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Config.scala +++ b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/Config.scala @@ -11,9 +11,13 @@ final case class Config( port: Int, packageContainer: DamlPackageContainer, mustFail: Boolean, + verbose: Boolean, timeoutScaleFactor: Double, extract: Boolean, - tlsConfig: Option[TlsConfiguration] + tlsConfig: Option[TlsConfiguration], + excluded: Set[String], + included: Set[String], + listTests: Boolean ) object Config { @@ -22,8 +26,12 @@ object Config { port = 6865, packageContainer = DamlPackageContainer(), mustFail = false, + verbose = false, timeoutScaleFactor = 1.0, extract = false, - tlsConfig = None + tlsConfig = None, + excluded = Set.empty, + included = Set.empty, + listTests = false ) -} \ No newline at end of file +} diff --git a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/LedgerApiTestTool.scala b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/LedgerApiTestTool.scala index 3f45a113f0..b2ef9f707a 100644 --- a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/LedgerApiTestTool.scala +++ b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/LedgerApiTestTool.scala @@ -6,18 +6,26 @@ package com.daml.ledger.api.testtool import java.io.File import java.nio.file.{Files, Path, Paths, StandardCopyOption} +import com.digitalasset.platform.PlatformApplications import com.digitalasset.platform.PlatformApplications.RemoteApiEndpoint import com.digitalasset.platform.common.LedgerIdMode import com.digitalasset.platform.semantictest.SandboxSemanticTestsLfRunner import com.digitalasset.platform.services.time.TimeProviderType import com.digitalasset.platform.testing.LedgerBackend -import org.scalatest.Args +import com.digitalasset.platform.tests.integration.ledger.api.TransactionServiceIT import org.scalatest.time.{Seconds, Span} +import org.scalatest.{Args, Suite} + +import scala.util.control.NonFatal object LedgerApiTestTool { - + val semanticTestsResource = "/ledger/ledger-api-integration-tests/SemanticTests.dar" + val integrationTestResource = "/ledger/sandbox/Test.dar" + val testResources = List( + integrationTestResource, + semanticTestsResource, + ) def main(args: Array[String]): Unit = { - val testResources = List("/ledger/ledger-api-integration-tests/SemanticTests.dar") val toolConfig = Cli .parse(args) @@ -25,53 +33,68 @@ object LedgerApiTestTool { if (toolConfig.extract) { extractTestFiles(testResources) - System.exit(0) + sys.exit(0) + } + + val commonConfig = PlatformApplications.Config.default + .withTimeProvider(TimeProviderType.WallClock) + .withLedgerIdMode(LedgerIdMode.Dynamic()) + .withRemoteApiEndpoint( + RemoteApiEndpoint.default + .withHost(toolConfig.host) + .withPort(toolConfig.port) + .withTlsConfig(toolConfig.tlsConfig)) + + val default = defaultTests(commonConfig) + val optional = optionalTests(commonConfig) + + val allTests = default ++ optional + + if (toolConfig.listTests) { + println("Tests marked with * are run by default.\n") + println(default.keySet.toSeq.sorted.map(_ + " *").mkString("\n")) + println(optional.keySet.toSeq.sorted.mkString("\n")) + sys.exit(0) } var failed = false try { - val integrationTestResourceStream = - testResources.headOption.map(getClass.getResourceAsStream(_)).flatMap(Option(_)) - require( - integrationTestResourceStream.isDefined, - "Unable to load the required test DAR from resources.") - val targetPath: Path = Files.createTempFile("ledger-api-test-tool-", "-test.dar") - Files.copy( - integrationTestResourceStream.get, - targetPath, - StandardCopyOption.REPLACE_EXISTING); + val testsToRun = (if (toolConfig.included.isEmpty) default.keySet else toolConfig.included) + .filterNot(toolConfig.excluded) - val reporter = new ToolReporter + if (testsToRun.isEmpty) { + println("No tests to run.") + sys.exit(0) + } + + val reporter = new ToolReporter(toolConfig.verbose) val sorter = new ToolSorter - var semanticTestsRunner = new SandboxSemanticTestsLfRunner { - override def suiteName: String = "Semantic Tests" - override def actorSystemName = "SandboxSemanticTestsLfRunnerTestToolActorSystem" + testsToRun + .find(n => !allTests.contains(n)) + .foreach { unknownSuite => + println(s"Unknown Test: $unknownSuite") + sys.exit(1) + } - override def fixtureIdsEnabled: Set[LedgerBackend] = - Set(LedgerBackend.RemoteApiProxy) - - override implicit lazy val patienceConfig: PatienceConfig = PatienceConfig( - Span(60L, Seconds)) - - override protected def config: Config = - Config.default - .withTimeProvider(TimeProviderType.WallClock) - .withLedgerIdMode(LedgerIdMode.Dynamic()) - .withRemoteApiEndpoint( - RemoteApiEndpoint.default - .withHost(toolConfig.host) - .withPort(toolConfig.port) - .withTlsConfig(toolConfig.tlsConfig)) - .withDarFile(targetPath) + testsToRun.foreach { suiteName => + try { + allTests(suiteName)() + .run(None, Args(reporter = reporter, distributedTestSorter = Some(sorter))) + } catch { + case NonFatal(t) => + failed = true + } + () } - semanticTestsRunner.run(None, Args(reporter = reporter, distributedTestSorter = Some(sorter))) + + failed |= reporter.statistics.testsStarted != reporter.statistics.testsSucceeded + reporter.printStatistics } catch { - case (t: Throwable) => + case NonFatal(t) if toolConfig.mustFail => failed = true - if (!toolConfig.mustFail) throw t } if (toolConfig.mustFail) { @@ -79,9 +102,66 @@ object LedgerApiTestTool { else throw new RuntimeException( "None of the scenarios failed, yet the --must-fail flag was specified!") + } else { + if (failed) { + sys.exit(1) + } } } + private def defaultTests(commonConfig: PlatformApplications.Config): Map[String, () => Suite] = { + val semanticTestsRunner = lazyInit( + "SemanticTests", + name => + new SandboxSemanticTestsLfRunner { + override def suiteName: String = name + + override def actorSystemName = s"${name}TestToolActorSystem" + + override def fixtureIdsEnabled: Set[LedgerBackend] = Set(LedgerBackend.RemoteApiProxy) + + override implicit lazy val patienceConfig: PatienceConfig = + PatienceConfig(Span(60L, Seconds)) + + override protected def config: Config = + commonConfig.withDarFile(resourceAsFile(semanticTestsResource)) + } + ) + Map(semanticTestsRunner) + } + private def optionalTests(commonConfig: PlatformApplications.Config): Map[String, () => Suite] = { + + val transactionServiceIT = lazyInit( + "TransactionServiceTests", + name => + new TransactionServiceIT { + override def suiteName: String = name + override def actorSystemName = s"${name}ToolActorSystem" + override def fixtureIdsEnabled: Set[LedgerBackend] = Set(LedgerBackend.RemoteApiProxy) + + override protected def config: Config = + commonConfig.withDarFile(resourceAsFile(integrationTestResource)) + } + ) + + Map(transactionServiceIT) + } + + def lazyInit[A](name: String, factory: String => A): (String, () => A) = { + (name, () => factory(name)) + } + + private def resourceAsFile(testResource: String): Path = { + val integrationTestResourceStream = + Option(getClass.getResourceAsStream(testResource)) + require( + integrationTestResourceStream.isDefined, + "Unable to load the required test DAR from resources.") + val targetPath: Path = Files.createTempFile("ledger-api-test-tool-", "-test.dar") + Files.copy(integrationTestResourceStream.get, targetPath, StandardCopyOption.REPLACE_EXISTING); + targetPath + } + private def extractTestFiles(testResources: List[String]): Unit = { val pwd = Paths.get(".").toAbsolutePath println(s"Extracting all DAML resources necessary to run the tests into $pwd.") diff --git a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/ToolReporter.scala b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/ToolReporter.scala index dc4b013d05..7c2e584054 100644 --- a/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/ToolReporter.scala +++ b/ledger/ledger-api-test-tool/src/main/scala/com/daml/ledger/api/testtool/ToolReporter.scala @@ -12,7 +12,12 @@ import org.scalatest.Reporter * Ledger API Test Tool CLI reporter. Implements scalatest's Reporter interface and prints out colorized reports to the * stdout. Supports very limited set of scalatest events. */ -class ToolReporter extends Reporter { +class ToolReporter(verbose: Boolean) extends Reporter { + case class Statistics( + testsStarted: Int, + testsSucceeded: Int, + testsCancelled: Int, + testsFailed: Int) final val ansiReset = "\u001b[0m" final val ansiBlue = "\u001b[34m" @@ -24,6 +29,10 @@ class ToolReporter extends Reporter { private def repeatChar(char: Char, n: Int) = char.toString * n private var depth = 0 + private var testsStarted = 0 + private var testsSucceeded = 0 + private var testsCancelled = 0 + private var testsFailed = 0 private def indented(s: String, extra: Integer = 0, prefix: Char = '-') = { s.split("\n").map(indentedSingle(_, extra, prefix)).mkString("\n") @@ -54,6 +63,7 @@ class ToolReporter extends Reporter { payload, threadName, timeStamp) => + testsStarted += 1 print(indented(ansiBlue + testText + "... ")) case e.TestSucceeded( @@ -71,6 +81,7 @@ class ToolReporter extends Reporter { payload, threadName, timeStamp) => + testsSucceeded += 1 println(ansiGreen + "✓") case e.TestCanceled( @@ -90,6 +101,7 @@ class ToolReporter extends Reporter { payload, threadName, timeStamp) => + testsCancelled += 1 println(ansiRed + "cancelled.") case e.TestFailed( @@ -109,13 +121,18 @@ class ToolReporter extends Reporter { payload, threadName, timeStamp) => + testsFailed += 1 println(ansiRed + "✗" + ansiReset) throwable match { case None => println(indented(ansiRed + s"Exception details missing!", 1, ' ')) case Some(e) => println(indented(s"Failure details:", 1, ' ')) - val st = ExceptionUtils.getStackTrace(e) + val st = if (verbose) { + ExceptionUtils.getStackTrace(e) + } else { + e.getMessage + } println(indented(st, 2, '|')) } @@ -151,4 +168,22 @@ class ToolReporter extends Reporter { print(ansiReset) } + def statistics = Statistics(testsStarted, testsSucceeded, testsCancelled, testsFailed) + + def printStatistics = { + statistics match { + case Statistics(0, _, _, _) => + println(ansiYellow + "No tests were run" + ansiReset) + case Statistics(a, s, 0, 0) => + println(ansiGreen + s"All ${s}/${a} tests were successful!" + ansiReset) + case Statistics(a, s, c, 0) => + println(ansiYellow + s"${s}/${a} tests were successful, but ${c} were skipped." + ansiReset) + case Statistics(a, s, 0, f) => + println(ansiRed + s"${s} were successful and ${f} failed out of ${a} tests." + ansiReset) + case _ => + println("BUG") + } + + } + }