From 220ccdbe13e750f171f4900538ec935f20cfaaa0 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 25 Nov 2016 15:26:00 +0000 Subject: [PATCH 1/5] docs: Add integration test tutorial --- docs/source/example-code/build.gradle | 19 +++ .../corda/docs/IntegrationTestingTutorial.kt | 112 ++++++++++++++++++ docs/source/index.rst | 1 + docs/source/tutorial-integration-testing.rst | 73 ++++++++++++ .../main/kotlin/net/corda/testing/Expect.kt | 2 + 5 files changed, 207 insertions(+) create mode 100644 docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt create mode 100644 docs/source/tutorial-integration-testing.rst diff --git a/docs/source/example-code/build.gradle b/docs/source/example-code/build.gradle index a5d0733652..919631dfa0 100644 --- a/docs/source/example-code/build.gradle +++ b/docs/source/example-code/build.gradle @@ -19,17 +19,31 @@ repositories { } } +configurations { + integrationTestCompile.extendsFrom testCompile + integrationTestRuntime.extendsFrom testRuntime +} + sourceSets { main { resources { srcDir "../../../config/dev" } } + + integrationTest { + kotlin { + compileClasspath += main.output + test.output + runtimeClasspath += main.output + test.output + srcDir file('src/integration-test/kotlin') + } + } } dependencies { compile project(':core') compile project(':client') + compile project(':test-utils') compile "org.graphstream:gs-core:1.3" compile("org.graphstream:gs-ui:1.3") { @@ -52,3 +66,8 @@ applicationDistribution.into("bin") { from(getClientRpcTutorial) fileMode = 0755 } + +task integrationTest(type: Test) { + testClassesDir = sourceSets.integrationTest.output.classesDir + classpath = sourceSets.integrationTest.runtimeClasspath +} \ No newline at end of file diff --git a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt new file mode 100644 index 0000000000..c00337aa36 --- /dev/null +++ b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt @@ -0,0 +1,112 @@ +package net.corda.docs + +import net.corda.client.CordaRPCClient +import net.corda.contracts.asset.Cash +import net.corda.core.contracts.DOLLARS +import net.corda.core.contracts.issuedBy +import net.corda.core.node.services.ServiceInfo +import net.corda.core.node.services.Vault +import net.corda.core.serialization.OpaqueBytes +import net.corda.flows.CashCommand +import net.corda.flows.CashFlow +import net.corda.flows.CashFlowResult +import net.corda.node.driver.driver +import net.corda.node.services.User +import net.corda.node.services.config.configureTestSSL +import net.corda.node.services.messaging.ArtemisMessagingComponent +import net.corda.node.services.messaging.startFlow +import net.corda.node.services.startFlowPermission +import net.corda.node.services.transactions.ValidatingNotaryService +import net.corda.testing.expect +import net.corda.testing.expectEvents +import net.corda.testing.parallel +import net.corda.testing.sequence +import org.junit.Test +import kotlin.concurrent.thread + +class IntegrationTestingTutorial { + + @Test + fun aliceBobCashExchangeExample() { + // START 1 + driver { + val testUser = User("testUser", "testPassword", permissions = setOf(startFlowPermission())) + val aliceFuture = startNode("Alice", rpcUsers = listOf(testUser)) + val bobFuture = startNode("Bob", rpcUsers = listOf(testUser)) + val notaryFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.Companion.type))) + val alice = aliceFuture.get() + val bob = bobFuture.get() + val notary = notaryFuture.get() + // END 1 + + // START 2 + val aliceClient = CordaRPCClient( + host = ArtemisMessagingComponent.Companion.toHostAndPort(alice.nodeInfo.address), + config = configureTestSSL() + ) + aliceClient.start("testUser", "testPassword") + val aliceProxy = aliceClient.proxy() + val bobClient = CordaRPCClient( + host = ArtemisMessagingComponent.Companion.toHostAndPort(bob.nodeInfo.address), + config = configureTestSSL() + ) + bobClient.start("testUser", "testPassword") + val bobProxy = bobClient.proxy() + // END 2 + + // START 3 + val bobVaultUpdates = bobProxy.vaultAndUpdates().second + val aliceVaultUpdates = aliceProxy.vaultAndUpdates().second + // END 3 + + // START 4 + val issueRef = OpaqueBytes.Companion.of(0) + for (i in 1 .. 10) { + thread { + aliceProxy.startFlow(::CashFlow, CashCommand.IssueCash( + amount = i.DOLLARS, + issueRef = issueRef, + recipient = bob.nodeInfo.legalIdentity, + notary = notary.nodeInfo.notaryIdentity + )) + } + } + + bobVaultUpdates.expectEvents { + parallel( + (1 .. 10).map { i -> + expect( + match = { update: Vault.Update -> + (update.produced.first().state.data as Cash.State).amount.quantity == i * 100L + } + ) { update -> + println("Bob vault update of $update") + } + } + ) + } + // END 4 + + // START 5 + for (i in 1 .. 10) { + val flowHandle = bobProxy.startFlow(::CashFlow, CashCommand.PayCash( + amount = i.DOLLARS.issuedBy(alice.nodeInfo.legalIdentity.ref(issueRef)), + recipient = alice.nodeInfo.legalIdentity + )) + require(flowHandle.returnValue.toBlocking().first() is CashFlowResult.Success) + } + + aliceVaultUpdates.expectEvents { + sequence( + (1 .. 10).map { i -> + expect { update: Vault.Update -> + println("Alice got vault update of $update") + require((update.produced.first().state.data as Cash.State).amount.quantity == i * 100L) + } + } + ) + } + } + } +} +// END 5 \ No newline at end of file diff --git a/docs/source/index.rst b/docs/source/index.rst index 3a789907bd..6b5a82f574 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -68,6 +68,7 @@ Read on to learn: tutorial-contract tutorial-contract-clauses tutorial-test-dsl + tutorial-integration-testing tutorial-clientrpc-api flow-state-machines flow-testing diff --git a/docs/source/tutorial-integration-testing.rst b/docs/source/tutorial-integration-testing.rst new file mode 100644 index 0000000000..310c444295 --- /dev/null +++ b/docs/source/tutorial-integration-testing.rst @@ -0,0 +1,73 @@ +Integration Test Tutorial +========================= + +Integration testing involves bringing up nodes locally and testing invariants about them by starting flows and inspecting their state. + +In this tutorial we will bring up three nodes Alice, Bob and a Notary. Alice will issue Cash to Bob, then Bob will send this Cash back to Alice. We will see how to test some simple deterministic and nondeterministic invariants in the meantime. + +In order to spawn nodes we will use the Driver DSL. This DSL allows one to start up node processes from code. It manages a network map service and safe shutting down of nodes in the background. + +.. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt + :language: kotlin + :start-after: START 1 + :end-before: END 1 + +The above code creates a ``User`` permissioned to start the ``CashFlow`` protocol. It then starts up Alice and Bob with this user, allowing us to later connect to the nodes. + +Then the notary is started up. Note that we need to add ``ValidatingNotaryService`` as an advertised service in order for this node to serve notary functionality. This is also where flows added in plugins should be specified. Note also that we won't connect to the notary directly, so there's no need to pass in the test ``User``. + +The ``startNode`` function returns a future that completes once the node is fully started. This allows starting of the nodes to be parallel. We wait on these futures as we need the information returned; their respective ``NodeInfo`` s. + +.. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt + :language: kotlin + :start-after: START 2 + :end-before: END 2 + +Next we connect to Alice and Bob respectively from the test process using the test user we created. Then we establish RPC links that allow us to start flows and query state. + +Note that Driver nodes start up with test server certificiates, so it's enough to pass in ``configureTestSSL()`` for the clients. + +.. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt + :language: kotlin + :start-after: START 3 + :end-before: END 3 + +We will be interested in changes to Alice's and Bob's vault, so we query a stream of vault updates from each. + +Now that we're all set up we can finally get some Cash action going! + +.. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt + :language: kotlin + :start-after: START 4 + :end-before: END 4 + +The first loop creates 10 threads, each starting a ``CashFlow`` flow on the Alice node. We specify that we want to issue ``i`` dollars to Bob, using the Notary as the notary responsible for notarising the created states. Note that no notarisation will occur yet as we're not spending any states, only entering new ones to the ledger. + +We started the flows from different threads for the sake of the tutorial, to demonstrate how to test non-determinism, which is what the ``expectEvents`` block does. + +The Expect DSL allows ordering constraints to be checked on a stream of events. The above code specifies that we are expecting 10 updates to be emitted on the ``bobVaultUpdates`` stream in unspecified order (this is what the ``parallel`` construct does). We specify a (otherwise optional) ``match`` predicate to identify specific updates we are interested in, which we then print. + +If we run the code written so far we should see 4 nodes starting up (Alice,Bob,Notary + implicit Network Map service), then 10 logs of Bob receiving 1,2,...10 dollars from Alice in some unspecified order. + +Next we want Bob to send this Cash back to Alice. + +.. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt + :language: kotlin + :start-after: START 5 + :end-before: END 5 + +This time we'll do it sequentially. We make Bob pay 1,2,..10 dollars to Alice in order. We make sure that a the ``CashFlow`` has finished by waiting on ``startFlow`` 's ``returnValue``. + +Then we use the Expect DSL again, this time using ``sequence`` to test for the updates arriving in the order we expect them to. + +Note that ``parallel`` and ``sequence`` may be nested into each other arbitrarily to test more complex scenarios. + +That's it! We saw how to start up several corda nodes locally, how to connect to them, and how to test some simple invariants about ``CashFlow``. + +To run the complete test you can open ``example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt`` from IntelliJ and run the test, or alternatively use gradle: + + +.. sourcecode:: bash + + # Run example-code integration tests + ./gradlew docs/source/example-code:integrationTest -i diff --git a/test-utils/src/main/kotlin/net/corda/testing/Expect.kt b/test-utils/src/main/kotlin/net/corda/testing/Expect.kt index e1ba96198f..709e77926f 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/Expect.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/Expect.kt @@ -67,6 +67,7 @@ inline fun expect( * @param expectations The pieces of DSL that should run sequentially when events arrive. */ fun sequence(vararg expectations: ExpectCompose): ExpectCompose = ExpectCompose.Sequential(listOf(*expectations)) +fun sequence(expectations: List>): ExpectCompose = ExpectCompose.Sequential(expectations) /** * Tests that events arrive in unspecified order. @@ -74,6 +75,7 @@ fun sequence(vararg expectations: ExpectCompose): ExpectCompose = Expe * @param expectations The pieces of DSL all of which should run but in an unspecified order depending on what sequence events arrive. */ fun parallel(vararg expectations: ExpectCompose): ExpectCompose = ExpectCompose.Parallel(listOf(*expectations)) +fun parallel(expectations: List>): ExpectCompose = ExpectCompose.Parallel(expectations) /** * Tests that N events of the same type arrive From 2bb1ecdfc1c53a6f099198369ebf1728342badb4 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 28 Nov 2016 11:50:12 +0000 Subject: [PATCH 2/5] docs: Add note on self-issuance example in integtest tutorial --- docs/source/tutorial-integration-testing.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/tutorial-integration-testing.rst b/docs/source/tutorial-integration-testing.rst index 310c444295..576db3a1bf 100644 --- a/docs/source/tutorial-integration-testing.rst +++ b/docs/source/tutorial-integration-testing.rst @@ -5,6 +5,8 @@ Integration testing involves bringing up nodes locally and testing invariants ab In this tutorial we will bring up three nodes Alice, Bob and a Notary. Alice will issue Cash to Bob, then Bob will send this Cash back to Alice. We will see how to test some simple deterministic and nondeterministic invariants in the meantime. +(Note that this example where Alice is self-issuing Cash is purely for demonstration purposes, in reality Cash would be issued by a bank and subsequently passed around.) + In order to spawn nodes we will use the Driver DSL. This DSL allows one to start up node processes from code. It manages a network map service and safe shutting down of nodes in the background. .. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt From c6a994aca2fbc5a0285b316ccedf92ed77eae22d Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 28 Nov 2016 11:58:14 +0000 Subject: [PATCH 3/5] docs: Add setting-up-a-corda-network to index.html --- docs/source/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/index.rst b/docs/source/index.rst index 6b5a82f574..544d236f08 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -95,6 +95,7 @@ Read on to learn: :caption: Appendix loadtesting + setting-up-a-corda-network secure-coding-guidelines release-process release-notes From d9023fd889b9e5aa64857708162fc508a43770c3 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 28 Nov 2016 13:37:38 +0000 Subject: [PATCH 4/5] docs: Line wrap integ test tutorial --- docs/source/tutorial-integration-testing.rst | 80 +++++++++++++++----- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/docs/source/tutorial-integration-testing.rst b/docs/source/tutorial-integration-testing.rst index 576db3a1bf..4cca59f009 100644 --- a/docs/source/tutorial-integration-testing.rst +++ b/docs/source/tutorial-integration-testing.rst @@ -1,40 +1,61 @@ Integration Test Tutorial ========================= -Integration testing involves bringing up nodes locally and testing invariants about them by starting flows and inspecting their state. +Integration testing involves bringing up nodes locally and testing +invariants about them by starting flows and inspecting their state. -In this tutorial we will bring up three nodes Alice, Bob and a Notary. Alice will issue Cash to Bob, then Bob will send this Cash back to Alice. We will see how to test some simple deterministic and nondeterministic invariants in the meantime. +In this tutorial we will bring up three nodes Alice, Bob and a +Notary. Alice will issue Cash to Bob, then Bob will send this Cash +back to Alice. We will see how to test some simple deterministic and +nondeterministic invariants in the meantime. -(Note that this example where Alice is self-issuing Cash is purely for demonstration purposes, in reality Cash would be issued by a bank and subsequently passed around.) +(Note that this example where Alice is self-issuing Cash is purely for +demonstration purposes, in reality Cash would be issued by a bank and +subsequently passed around.) -In order to spawn nodes we will use the Driver DSL. This DSL allows one to start up node processes from code. It manages a network map service and safe shutting down of nodes in the background. +In order to spawn nodes we will use the Driver DSL. This DSL allows +one to start up node processes from code. It manages a network map +service and safe shutting down of nodes in the background. .. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt :language: kotlin :start-after: START 1 :end-before: END 1 -The above code creates a ``User`` permissioned to start the ``CashFlow`` protocol. It then starts up Alice and Bob with this user, allowing us to later connect to the nodes. +The above code creates a ``User`` permissioned to start the +``CashFlow`` protocol. It then starts up Alice and Bob with this user, +allowing us to later connect to the nodes. -Then the notary is started up. Note that we need to add ``ValidatingNotaryService`` as an advertised service in order for this node to serve notary functionality. This is also where flows added in plugins should be specified. Note also that we won't connect to the notary directly, so there's no need to pass in the test ``User``. +Then the notary is started up. Note that we need to add +``ValidatingNotaryService`` as an advertised service in order for this +node to serve notary functionality. This is also where flows added in +plugins should be specified. Note also that we won't connect to the +notary directly, so there's no need to pass in the test ``User``. -The ``startNode`` function returns a future that completes once the node is fully started. This allows starting of the nodes to be parallel. We wait on these futures as we need the information returned; their respective ``NodeInfo`` s. +The ``startNode`` function returns a future that completes once the +node is fully started. This allows starting of the nodes to be +parallel. We wait on these futures as we need the information +returned; their respective ``NodeInfo`` s. .. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt :language: kotlin :start-after: START 2 :end-before: END 2 -Next we connect to Alice and Bob respectively from the test process using the test user we created. Then we establish RPC links that allow us to start flows and query state. +Next we connect to Alice and Bob respectively from the test process +using the test user we created. Then we establish RPC links that allow +us to start flows and query state. -Note that Driver nodes start up with test server certificiates, so it's enough to pass in ``configureTestSSL()`` for the clients. +Note that Driver nodes start up with test server certificiates, so +it's enough to pass in ``configureTestSSL()`` for the clients. .. literalinclude:: example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt :language: kotlin :start-after: START 3 :end-before: END 3 -We will be interested in changes to Alice's and Bob's vault, so we query a stream of vault updates from each. +We will be interested in changes to Alice's and Bob's vault, so we +query a stream of vault updates from each. Now that we're all set up we can finally get some Cash action going! @@ -43,13 +64,26 @@ Now that we're all set up we can finally get some Cash action going! :start-after: START 4 :end-before: END 4 -The first loop creates 10 threads, each starting a ``CashFlow`` flow on the Alice node. We specify that we want to issue ``i`` dollars to Bob, using the Notary as the notary responsible for notarising the created states. Note that no notarisation will occur yet as we're not spending any states, only entering new ones to the ledger. +The first loop creates 10 threads, each starting a ``CashFlow`` flow +on the Alice node. We specify that we want to issue ``i`` dollars to +Bob, using the Notary as the notary responsible for notarising the +created states. Note that no notarisation will occur yet as we're not +spending any states, only entering new ones to the ledger. -We started the flows from different threads for the sake of the tutorial, to demonstrate how to test non-determinism, which is what the ``expectEvents`` block does. +We started the flows from different threads for the sake of the +tutorial, to demonstrate how to test non-determinism, which is what +the ``expectEvents`` block does. -The Expect DSL allows ordering constraints to be checked on a stream of events. The above code specifies that we are expecting 10 updates to be emitted on the ``bobVaultUpdates`` stream in unspecified order (this is what the ``parallel`` construct does). We specify a (otherwise optional) ``match`` predicate to identify specific updates we are interested in, which we then print. +The Expect DSL allows ordering constraints to be checked on a stream +of events. The above code specifies that we are expecting 10 updates +to be emitted on the ``bobVaultUpdates`` stream in unspecified order +(this is what the ``parallel`` construct does). We specify a +(otherwise optional) ``match`` predicate to identify specific updates +we are interested in, which we then print. -If we run the code written so far we should see 4 nodes starting up (Alice,Bob,Notary + implicit Network Map service), then 10 logs of Bob receiving 1,2,...10 dollars from Alice in some unspecified order. +If we run the code written so far we should see 4 nodes starting up +(Alice,Bob,Notary + implicit Network Map service), then 10 logs of Bob +receiving 1,2,...10 dollars from Alice in some unspecified order. Next we want Bob to send this Cash back to Alice. @@ -58,15 +92,23 @@ Next we want Bob to send this Cash back to Alice. :start-after: START 5 :end-before: END 5 -This time we'll do it sequentially. We make Bob pay 1,2,..10 dollars to Alice in order. We make sure that a the ``CashFlow`` has finished by waiting on ``startFlow`` 's ``returnValue``. +This time we'll do it sequentially. We make Bob pay 1,2,..10 dollars +to Alice in order. We make sure that a the ``CashFlow`` has finished +by waiting on ``startFlow`` 's ``returnValue``. -Then we use the Expect DSL again, this time using ``sequence`` to test for the updates arriving in the order we expect them to. +Then we use the Expect DSL again, this time using ``sequence`` to test +for the updates arriving in the order we expect them to. -Note that ``parallel`` and ``sequence`` may be nested into each other arbitrarily to test more complex scenarios. +Note that ``parallel`` and ``sequence`` may be nested into each other +arbitrarily to test more complex scenarios. -That's it! We saw how to start up several corda nodes locally, how to connect to them, and how to test some simple invariants about ``CashFlow``. +That's it! We saw how to start up several corda nodes locally, how to +connect to them, and how to test some simple invariants about +``CashFlow``. -To run the complete test you can open ``example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt`` from IntelliJ and run the test, or alternatively use gradle: +To run the complete test you can open +``example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt`` +from IntelliJ and run the test, or alternatively use gradle: .. sourcecode:: bash From 53a825e4cc7e05817b4eccb542418d7d81852128 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Mon, 28 Nov 2016 13:43:51 +0000 Subject: [PATCH 5/5] docs: Address PR 553 comments --- .../net/corda/docs/IntegrationTestingTutorial.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt index c00337aa36..64b2902048 100644 --- a/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt +++ b/docs/source/example-code/src/integration-test/kotlin/net/corda/docs/IntegrationTestingTutorial.kt @@ -23,6 +23,7 @@ import net.corda.testing.parallel import net.corda.testing.sequence import org.junit.Test import kotlin.concurrent.thread +import kotlin.test.assertEquals class IntegrationTestingTutorial { @@ -33,7 +34,7 @@ class IntegrationTestingTutorial { val testUser = User("testUser", "testPassword", permissions = setOf(startFlowPermission())) val aliceFuture = startNode("Alice", rpcUsers = listOf(testUser)) val bobFuture = startNode("Bob", rpcUsers = listOf(testUser)) - val notaryFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.Companion.type))) + val notaryFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(ValidatingNotaryService.type))) val alice = aliceFuture.get() val bob = bobFuture.get() val notary = notaryFuture.get() @@ -41,13 +42,13 @@ class IntegrationTestingTutorial { // START 2 val aliceClient = CordaRPCClient( - host = ArtemisMessagingComponent.Companion.toHostAndPort(alice.nodeInfo.address), + host = ArtemisMessagingComponent.toHostAndPort(alice.nodeInfo.address), config = configureTestSSL() ) aliceClient.start("testUser", "testPassword") val aliceProxy = aliceClient.proxy() val bobClient = CordaRPCClient( - host = ArtemisMessagingComponent.Companion.toHostAndPort(bob.nodeInfo.address), + host = ArtemisMessagingComponent.toHostAndPort(bob.nodeInfo.address), config = configureTestSSL() ) bobClient.start("testUser", "testPassword") @@ -60,7 +61,7 @@ class IntegrationTestingTutorial { // END 3 // START 4 - val issueRef = OpaqueBytes.Companion.of(0) + val issueRef = OpaqueBytes.of(0) for (i in 1 .. 10) { thread { aliceProxy.startFlow(::CashFlow, CashCommand.IssueCash( @@ -93,7 +94,7 @@ class IntegrationTestingTutorial { amount = i.DOLLARS.issuedBy(alice.nodeInfo.legalIdentity.ref(issueRef)), recipient = alice.nodeInfo.legalIdentity )) - require(flowHandle.returnValue.toBlocking().first() is CashFlowResult.Success) + assert(flowHandle.returnValue.toBlocking().first() is CashFlowResult.Success) } aliceVaultUpdates.expectEvents { @@ -101,7 +102,7 @@ class IntegrationTestingTutorial { (1 .. 10).map { i -> expect { update: Vault.Update -> println("Alice got vault update of $update") - require((update.produced.first().state.data as Cash.State).amount.quantity == i * 100L) + assertEquals((update.produced.first().state.data as Cash.State).amount.quantity, i * 100L) } } )