diff --git a/docs/source/api-contract-constraints.rst b/docs/source/api-contract-constraints.rst index 5dc16ef8c9..2fc81d0e98 100644 --- a/docs/source/api-contract-constraints.rst +++ b/docs/source/api-contract-constraints.rst @@ -311,70 +311,6 @@ For example: For Contracts that are annotated with ``@NoConstraintPropagation``, the platform requires that the Transaction Builder specifies an actual constraint for the output states (the ``AutomaticPlaceholderConstraint`` can't be used) . - -Testing -------- - -Since all tests involving transactions now require attachments it is also required to load the correct attachments -for tests. Unit test environments in JVM ecosystems tend to use class directories rather than JARs, and so CorDapp JARs -typically aren't built for testing. Requiring this would add significant complexity to the build systems of Corda -and CorDapps, so the test suite has a set of convenient functions to generate CorDapps from package names or -to specify JAR URLs in the case that the CorDapp(s) involved in testing already exist. You can also just use -``AlwaysAcceptAttachmentConstraint`` in your tests to disable the constraints mechanism. - -MockNetwork/MockNode -******************** - -The simplest way to ensure that a vanilla instance of a MockNode generates the correct CorDapps is to use the -``cordappPackages`` constructor parameter (Kotlin) or the ``setCordappPackages`` method on ``MockNetworkParameters`` (Java) -when creating the MockNetwork. This will cause the ``AbstractNode`` to use the named packages as sources for CorDapps. All files -within those packages will be zipped into a JAR and added to the attachment store and loaded as CorDapps by the -``CordappLoader``. - -An example of this usage would be: - -.. sourcecode:: java - - class SomeTestClass { - MockNetwork network = null; - - @Before - void setup() { - network = new MockNetwork(new MockNetworkParameters().setCordappPackages(Arrays.asList("com.domain.cordapp"))) - } - - ... // Your tests go here - } - - -MockServices -************ - -If your test uses a ``MockServices`` directly you can instantiate it using a constructor that takes a list of packages -to use as CorDapps using the ``cordappPackages`` parameter. - -.. sourcecode:: java - - MockServices mockServices = new MockServices(Arrays.asList("com.domain.cordapp")) - -However - there is an easier way! If your unit tests are in the same package as the contract code itself, then you -can use the no-args constructor of ``MockServices``. The package to be scanned for CorDapps will be the same as the -the package of the class that constructed the object. This is a convenient default. - -Driver -****** - -The driver takes a parameter called ``extraCordappPackagesToScan`` which is a list of packages to use as CorDapps. - -.. sourcecode:: java - - driver(new DriverParameters().setExtraCordappPackagesToScan(Arrays.asList("com.domain.cordapp"))) ... - -Full Nodes -********** - -When testing against full nodes simply place your CorDapp into the cordapps directory of the node. - Debugging --------- If an attachment constraint cannot be resolved, a ``MissingContractAttachments`` exception is thrown. There are two diff --git a/docs/source/api-testing.rst b/docs/source/api-testing.rst index f72fb2750f..ae261a0e08 100644 --- a/docs/source/api-testing.rst +++ b/docs/source/api-testing.rst @@ -22,108 +22,20 @@ A ``MockNetwork`` is created as follows: .. container:: codeset - .. sourcecode:: kotlin + .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt + :language: kotlin + :start-after: DOCSTART 1 + :end-before: DOCEND 1 - class FlowTests { - private lateinit var mockNet: MockNetwork + .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java + :language: java + :start-after: DOCSTART 1 + :end-before: DOCEND 1 - @Before - fun setup() { - network = MockNetwork(listOf("my.cordapp.package", "my.other.cordapp.package")) - } - } +The ``MockNetwork`` requires at a minimum a list of CorDapps to be installed on each ``StartedMockNode``. The CorDapps are looked up on the +classpath by package name, using ``TestCordapp.findCordapp``. - - .. sourcecode:: java - - public class IOUFlowTests { - private MockNetwork network; - - @Before - public void setup() { - network = new MockNetwork(ImmutableList.of("my.cordapp.package", "my.other.cordapp.package")); - } - } - -The ``MockNetwork`` requires at a minimum a list of packages. Each package is packaged into a CorDapp JAR and installed -as a CorDapp on each ``StartedMockNode``. - -Configuring the ``MockNetwork`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``MockNetwork`` is configured automatically. You can tweak its configuration using a ``MockNetworkParameters`` -object, or by using named parameters in Kotlin: - -.. container:: codeset - - .. sourcecode:: kotlin - - val network = MockNetwork( - // A list of packages to scan. Any contracts, flows and Corda services within these - // packages will be automatically available to any nodes within the mock network - cordappPackages = listOf("my.cordapp.package", "my.other.cordapp.package"), - // If true then each node will be run in its own thread. This can result in race conditions in your - // code if not carefully written, but is more realistic and may help if you have flows in your app that - // do long blocking operations. - threadPerNode = false, - // The notaries to use on the mock network. By default you get one mock notary and that is usually - // sufficient. - notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME)), - // If true then messages will not be routed from sender to receiver until you use the - // [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code that can - // examine the state of the mock network before and after a message is sent, without races and without - // the receiving node immediately sending a response. - networkSendManuallyPumped = false, - // How traffic is allocated in the case where multiple nodes share a single identity, which happens for - // notaries in a cluster. You don't normally ever need to change this: it is mostly useful for testing - // notary implementations. - servicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random()) - - val network2 = MockNetwork( - // A list of packages to scan. Any contracts, flows and Corda services within these - // packages will be automatically available to any nodes within the mock network - listOf("my.cordapp.package", "my.other.cordapp.package"), MockNetworkParameters( - // If true then each node will be run in its own thread. This can result in race conditions in your - // code if not carefully written, but is more realistic and may help if you have flows in your app that - // do long blocking operations. - threadPerNode = false, - // The notaries to use on the mock network. By default you get one mock notary and that is usually - // sufficient. - notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME)), - // If true then messages will not be routed from sender to receiver until you use the - // [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code that can - // examine the state of the mock network before and after a message is sent, without races and without - // the receiving node immediately sending a response. - networkSendManuallyPumped = false, - // How traffic is allocated in the case where multiple nodes share a single identity, which happens for - // notaries in a cluster. You don't normally ever need to change this: it is mostly useful for testing - // notary implementations. - servicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random()) - ) - - .. sourcecode:: java - - MockNetwork network = MockNetwork( - // A list of packages to scan. Any contracts, flows and Corda services within these - // packages will be automatically available to any nodes within the mock network - ImmutableList.of("my.cordapp.package", "my.other.cordapp.package"), - new MockNetworkParameters() - // If true then each node will be run in its own thread. This can result in race conditions in - // your code if not carefully written, but is more realistic and may help if you have flows in - // your app that do long blocking operations. - .setThreadPerNode(false) - // The notaries to use on the mock network. By default you get one mock notary and that is - // usually sufficient. - .setNotarySpecs(ImmutableList.of(new MockNetworkNotarySpec(DUMMY_NOTARY_NAME))) - // If true then messages will not be routed from sender to receiver until you use the - // [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code - // that can examine the state of the mock network before and after a message is sent, without - // races and without the receiving node immediately sending a response. - .setNetworkSendManuallyPumped(false) - // How traffic is allocated in the case where multiple nodes share a single identity, which - // happens for notaries in a cluster. You don't normally ever need to change this: it is mostly - // useful for testing notary implementations. - .setServicePeerAllocationStrategy(new InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random())); +``MockNetworkParameters`` provides other properties for the network which can be tweaked. They default to sensible values if not specified. Adding nodes to the network ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,73 +44,21 @@ Nodes are created on the ``MockNetwork`` using: .. container:: codeset - .. sourcecode:: kotlin + .. literalinclude:: ../../docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt + :language: kotlin + :start-after: DOCSTART 2 + :end-before: DOCEND 2 - class FlowTests { - private lateinit var mockNet: MockNetwork - lateinit var nodeA: StartedMockNode - lateinit var nodeB: StartedMockNode + .. literalinclude:: ../../docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java + :language: java + :start-after: DOCSTART 2 + :end-before: DOCEND 2 - @Before - fun setup() { - network = MockNetwork(listOf("my.cordapp.package", "my.other.cordapp.package")) - nodeA = network.createPartyNode() - // We can optionally give the node a name. - nodeB = network.createPartyNode(CordaX500Name("Bank B", "London", "GB")) - } - } - - - .. sourcecode:: java - - public class IOUFlowTests { - private MockNetwork network; - private StartedMockNode a; - private StartedMockNode b; - - @Before - public void setup() { - network = new MockNetwork(ImmutableList.of("my.cordapp.package", "my.other.cordapp.package")); - nodeA = network.createPartyNode(null); - // We can optionally give the node a name. - nodeB = network.createPartyNode(new CordaX500Name("Bank B", "London", "GB")); - } - } - -Nodes added using ``createPartyNode`` are provided a default set of node parameters. However, it is also possible to -provide different parameters to each node using the following methods on ``MockNetwork``: - -.. container:: codeset - - .. sourcecode:: kotlin - - /** - * Create a started node with the given parameters. - * - * @param legalName The node's legal name. - * @param forcedID A unique identifier for the node. - * @param entropyRoot The initial entropy value to use when generating keys. Defaults to an (insecure) random value, - * but can be overridden to cause nodes to have stable or colliding identity/service keys. - * @param configOverrides Add/override the default configuration/behaviour of the node - * @param extraCordappPackages Extra CorDapp packages to add for this node. - */ - @JvmOverloads - fun createNode(legalName: CordaX500Name? = null, - forcedID: Int? = null, - entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), - configOverrides: MockNodeConfigOverrides? = null, - extraCordappPackages: List = emptyList() - ): StartedMockNode - - /** Create a started node with the given parameters. **/ - fun createNode(parameters: MockNodeParameters = MockNodeParameters()): StartedMockNode - -As you can see above, parameters can be added individually or encapsulated within a ``MockNodeParameters`` object. Of -particular interest are ``configOverrides`` which allow you to override some of the default node -configuration options. Please refer to the ``MockNodeConfigOverrides`` class for details what can currently be overridden. -Also, the ``extraCordappPackages`` parameter allows you to add extra CorDapps to a -specific node. This is useful when you wish for all nodes to load a common CorDapp but for a subset of nodes to load -CorDapps specific to their role in the network. +Nodes added using ``createNode`` are provided a default set of node parameters. However, it is also possible to +provide different parameters to each node using ``MockNodeParameters``. Of particular interest are ``configOverrides`` which allow you to +override some of the default node configuration options. Please refer to the ``MockNodeConfigOverrides`` class for details what can currently +be overridden. Also, the ``additionalCordapps`` parameter allows you to add extra CorDapps to a specific node. This is useful when you wish +for all nodes to load a common CorDapp but for a subset of nodes to load CorDapps specific to their role in the network. Running the network ^^^^^^^^^^^^^^^^^^^ diff --git a/docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java b/docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java new file mode 100644 index 0000000000..6ee5480d67 --- /dev/null +++ b/docs/source/example-code/src/main/java/net/corda/docs/java/MockNetworkTestsTutorial.java @@ -0,0 +1,35 @@ +package net.corda.docs.java; + +// DOCSTART 1 +import net.corda.core.identity.CordaX500Name; +import net.corda.testing.node.MockNetwork; +import net.corda.testing.node.MockNetworkParameters; +import net.corda.testing.node.StartedMockNode; +import org.junit.After; +import org.junit.Before; + +import static java.util.Collections.singletonList; +import static net.corda.testing.node.TestCordapp.findCordapp; + +public class MockNetworkTestsTutorial { + + private final MockNetwork mockNet = new MockNetwork(new MockNetworkParameters(singletonList(findCordapp("com.mycordapp.package")))); + + @After + public void cleanUp() { + mockNet.stopNodes(); + } +// DOCEND 1 + +// DOCSTART 2 + private StartedMockNode nodeA; + private StartedMockNode nodeB; + + @Before + public void setUp() { + nodeA = mockNet.createNode(); + // We can optionally give the node a name. + nodeB = mockNet.createNode(new CordaX500Name("Bank B", "London", "GB")); + } +// DOCEND 2 +} diff --git a/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt new file mode 100644 index 0000000000..1a22076d9c --- /dev/null +++ b/docs/source/example-code/src/main/kotlin/net/corda/docs/kotlin/MockNetworkTestsTutorial.kt @@ -0,0 +1,33 @@ +package net.corda.docs.kotlin + +// DOCSTART 1 +import net.corda.core.identity.CordaX500Name +import net.corda.testing.node.MockNetwork +import net.corda.testing.node.MockNetworkParameters +import net.corda.testing.node.StartedMockNode +import net.corda.testing.node.TestCordapp.Companion.findCordapp +import org.junit.After +import org.junit.Before + +class MockNetworkTestsTutorial { + + private val mockNet = MockNetwork(MockNetworkParameters(listOf(findCordapp("com.mycordapp.package")))) + + @After + fun cleanUp() { + mockNet.stopNodes() + } +// DOCEND 1 + +// DOCSTART 2 + private lateinit var nodeA: StartedMockNode + private lateinit var nodeB: StartedMockNode + + @Before + fun setUp() { + nodeA = mockNet.createNode() + // We can optionally give the node a name. + nodeB = mockNet.createNode(CordaX500Name("Bank B", "London", "GB")) + } +// DOCEND 2 +} diff --git a/docs/source/oracles.rst b/docs/source/oracles.rst index 5066fe2f93..e9c7198c84 100644 --- a/docs/source/oracles.rst +++ b/docs/source/oracles.rst @@ -269,19 +269,10 @@ Here's an example of it in action from ``FixingFlow.Fixer``. Testing ------- -The ``MockNetwork`` allows the creation of ``MockNode`` instances, which are simplified nodes which can be used for -testing (see :doc:`api-testing`). When creating the ``MockNetwork`` you supply a list of packages to scan for CorDapps. -Make sure the packages you provide include your oracle service, and it automatically be installed in the test nodes. -Then you can create an oracle node on the ``MockNetwork`` and insert any initialisation logic you want to use. In this -case, our ``Oracle`` service is in the ``net.corda.irs.api`` package, so the following test setup will install -the service in each node. Then an oracle node with an oracle service which is initialised with some data is created on -the mock network: - -.. literalinclude:: ../../samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/OracleNodeTearOffTests.kt - :language: kotlin - :start-after: DOCSTART 1 - :end-before: DOCEND 1 - :dedent: 4 +The ``MockNetwork`` allows the creation of ``MockNode`` instances, which are simplified nodes which can be used for testing (see :doc:`api-testing`). +When creating the ``MockNetwork`` you supply a list of ``TestCordapp`` objects which point to CorDapps on +the classpath. These CorDapps will be installed on each node on the network. Make sure the packages you provide reference to the CorDapp +containing your oracle service. You can then write tests on your mock network to verify the nodes interact with your Oracle correctly. diff --git a/node/src/test/kotlin/net/corda/node/internal/FlowRegistrationTest.kt b/node/src/test/kotlin/net/corda/node/internal/FlowRegistrationTest.kt index f375d91998..0bbb43147e 100644 --- a/node/src/test/kotlin/net/corda/node/internal/FlowRegistrationTest.kt +++ b/node/src/test/kotlin/net/corda/node/internal/FlowRegistrationTest.kt @@ -10,6 +10,7 @@ import net.corda.core.identity.Party import net.corda.core.utilities.unwrap import net.corda.testing.core.singleIdentity import net.corda.testing.node.MockNetwork +import net.corda.testing.node.MockNetworkParameters import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.StartedMockNode import org.junit.After @@ -26,7 +27,7 @@ class FlowRegistrationTest { @Before fun setup() { // no cordapps scanned so it can be tested in isolation - mockNetwork = MockNetwork() + mockNetwork = MockNetwork(MockNetworkParameters()) initiator = mockNetwork.createNode(MockNodeParameters(legalName = CordaX500Name("initiator", "Reading", "GB"))) responder = mockNetwork.createNode(MockNodeParameters(legalName = CordaX500Name("responder", "Reading", "GB"))) mockNetwork.runNetwork() diff --git a/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/OracleNodeTearOffTests.kt b/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/OracleNodeTearOffTests.kt index e77a092913..93ccb99ff6 100644 --- a/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/OracleNodeTearOffTests.kt +++ b/samples/irs-demo/cordapp/src/test/kotlin/net/corda/irs/api/OracleNodeTearOffTests.kt @@ -68,7 +68,7 @@ class OracleNodeTearOffTests { mockNet.stopNodes() } - // DOCSTART 2 + // DOCSTART 1 @Test fun `verify that the oracle signs the transaction if the interest rate within allowed limit`() { // Create a partial transaction @@ -93,7 +93,7 @@ class OracleNodeTearOffTests { // Check that the transaction has been signed by the oracle assertContains(fix.signers, oracle.owningKey) } - // DOCEND 2 + // DOCEND 1 @Test fun `verify that the oracle rejects the transaction if the interest rate is outside the allowed limit`() { diff --git a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt index d1e3ad1eaf..52ae6cbe69 100644 --- a/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt +++ b/testing/node-driver/src/integration-test/kotlin/net/corda/testing/node/MockNetworkIntegrationTests.kt @@ -10,7 +10,7 @@ class MockNetworkIntegrationTests { companion object { @JvmStatic fun main(args: Array) { - MockNetwork().run { + MockNetwork(MockNetworkParameters()).run { repeat(2) { createNode() } runNetwork() stopNodes() diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt index d8299d0cb0..1b98472fec 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/driver/Driver.kt @@ -248,7 +248,9 @@ data class DriverParameters( val notaryCustomOverrides: Map = emptyMap(), val inMemoryDB: Boolean = true, val cordappsForAllNodes: Collection? = null - ) { +) { + constructor(cordappsForAllNodes: Collection) : this(isDebug = false, cordappsForAllNodes = cordappsForAllNodes) + constructor( isDebug: Boolean = false, driverDirectory: Path = Paths.get("build") / "node-driver" / getTimestampAsDirectoryName(), @@ -313,38 +315,6 @@ data class DriverParameters( cordappsForAllNodes = null ) - constructor( - isDebug: Boolean, - driverDirectory: Path, - portAllocation: PortAllocation, - debugPortAllocation: PortAllocation, - systemProperties: Map, - useTestClock: Boolean, - startNodesInProcess: Boolean, - waitForAllNodesToFinish: Boolean, - notarySpecs: List, - extraCordappPackagesToScan: List, - jmxPolicy: JmxPolicy, - networkParameters: NetworkParameters, - cordappsForAllNodes: Collection? = null - ) : this( - isDebug, - driverDirectory, - portAllocation, - debugPortAllocation, - systemProperties, - useTestClock, - startNodesInProcess, - waitForAllNodesToFinish, - notarySpecs, - extraCordappPackagesToScan, - jmxPolicy, - networkParameters, - emptyMap(), - true, - cordappsForAllNodes - ) - constructor( isDebug: Boolean, driverDirectory: Path, @@ -377,39 +347,6 @@ data class DriverParameters( cordappsForAllNodes = null ) - constructor( - isDebug: Boolean, - driverDirectory: Path, - portAllocation: PortAllocation, - debugPortAllocation: PortAllocation, - systemProperties: Map, - useTestClock: Boolean, - startNodesInProcess: Boolean, - waitForAllNodesToFinish: Boolean, - notarySpecs: List, - extraCordappPackagesToScan: List, - jmxPolicy: JmxPolicy, - networkParameters: NetworkParameters, - inMemoryDB: Boolean, - cordappsForAllNodes: Set? = null - ) : this( - isDebug, - driverDirectory, - portAllocation, - debugPortAllocation, - systemProperties, - useTestClock, - startNodesInProcess, - waitForAllNodesToFinish, - notarySpecs, - extraCordappPackagesToScan, - jmxPolicy, - networkParameters, - emptyMap(), - inMemoryDB, - cordappsForAllNodes - ) - fun withIsDebug(isDebug: Boolean): DriverParameters = copy(isDebug = isDebug) fun withDriverDirectory(driverDirectory: Path): DriverParameters = copy(driverDirectory = driverDirectory) fun withPortAllocation(portAllocation: PortAllocation): DriverParameters = copy(portAllocation = portAllocation) @@ -419,6 +356,8 @@ data class DriverParameters( fun withStartNodesInProcess(startNodesInProcess: Boolean): DriverParameters = copy(startNodesInProcess = startNodesInProcess) fun withWaitForAllNodesToFinish(waitForAllNodesToFinish: Boolean): DriverParameters = copy(waitForAllNodesToFinish = waitForAllNodesToFinish) fun withNotarySpecs(notarySpecs: List): DriverParameters = copy(notarySpecs = notarySpecs) + @Deprecated("extraCordappPackagesToScan does not preserve the original CorDapp's versioning and metadata, which may lead to " + + "misleading results in tests. Use withCordappsForAllNodes instead.") fun withExtraCordappPackagesToScan(extraCordappPackagesToScan: List): DriverParameters = copy(extraCordappPackagesToScan = extraCordappPackagesToScan) fun withJmxPolicy(jmxPolicy: JmxPolicy): DriverParameters = copy(jmxPolicy = jmxPolicy) fun withNetworkParameters(networkParameters: NetworkParameters): DriverParameters = copy(networkParameters = networkParameters) diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetwork.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetwork.kt index 5f55b92310..eb23b72146 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetwork.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/MockNetwork.kt @@ -61,8 +61,7 @@ data class MockNodeParameters( } /** - * Immutable builder for configuring a [MockNetwork]. Kotlin users can also use named parameters to the constructor - * of [MockNetwork], which is more convenient. + * Immutable builder for configuring a [MockNetwork]. * * @property networkSendManuallyPumped If false then messages will not be routed from sender to receiver until you use * the [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code that can examine the @@ -95,6 +94,8 @@ data class MockNetworkParameters( networkParameters: NetworkParameters ) : this(networkSendManuallyPumped, threadPerNode, servicePeerAllocationStrategy, notarySpecs, networkParameters, emptyList()) + constructor(cordappsForAllNodes: Collection) : this(threadPerNode = false, cordappsForAllNodes = cordappsForAllNodes) + fun withNetworkParameters(networkParameters: NetworkParameters): MockNetworkParameters = copy(networkParameters = networkParameters) fun withNetworkSendManuallyPumped(networkSendManuallyPumped: Boolean): MockNetworkParameters = copy(networkSendManuallyPumped = networkSendManuallyPumped) fun withThreadPerNode(threadPerNode: Boolean): MockNetworkParameters = copy(threadPerNode = threadPerNode) @@ -108,7 +109,8 @@ data class MockNetworkParameters( threadPerNode: Boolean, servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy, notarySpecs: List, - networkParameters: NetworkParameters): MockNetworkParameters { + networkParameters: NetworkParameters + ): MockNetworkParameters { return MockNetworkParameters(networkSendManuallyPumped, threadPerNode, servicePeerAllocationStrategy, notarySpecs, networkParameters, emptyList()) } } @@ -243,9 +245,9 @@ class StartedMockNode private constructor(private val node: TestStartedNode) { * By default a single notary node is automatically started, which forms part of the network parameters for all the nodes. * This node is available by calling [defaultNotaryNode]. * + * @property defaultParameters The default parameters for the network. If any of the remaining constructor parameters are specified then + * their values are taken instead of the corresponding value in [defaultParameters]. * @property cordappPackages A [List] of cordapp packages to scan for any cordapp code, e.g. contract verification code, flows and services. - * @property defaultParameters A [MockNetworkParameters] object which contains the same parameters as the constructor, provided - * as a convenience for Java users. * @property networkSendManuallyPumped If false then messages will not be routed from sender to receiver until you use * the [MockNetwork.runNetwork] method. This is useful for writing single-threaded unit test code that can examine the * state of the mock network before and after a message is sent, without races and without the receiving node immediately @@ -279,8 +281,7 @@ open class MockNetwork( cordappPackages, defaultParameters = parameters ) - @JvmOverloads - constructor(parameters: MockNetworkParameters = MockNetworkParameters()) : this(emptyList(), parameters) + constructor(parameters: MockNetworkParameters) : this(emptyList(), defaultParameters = parameters) private val internalMockNetwork = InternalMockNetwork( cordappPackages, @@ -317,7 +318,7 @@ open class MockNetwork( fun createPartyNode(legalName: CordaX500Name? = null): StartedMockNode = StartedMockNode.create(internalMockNetwork.createPartyNode(legalName)) /** Create a started node with the given parameters. **/ - fun createNode(parameters: MockNodeParameters = MockNodeParameters()): StartedMockNode { + fun createNode(parameters: MockNodeParameters): StartedMockNode { return StartedMockNode.create(internalMockNetwork.createNode(InternalMockNodeParameters(parameters))) } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt index c4f986e049..7bfb67d338 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/TestCordapp.kt @@ -6,7 +6,7 @@ import net.corda.testing.driver.NodeParameters import net.corda.testing.node.internal.TestCordappImpl /** - * Encapsulates a CorDapp that exists on the current classpath, which can be pulled in for testing. Use [TestCordapp.Factory.findCordapp] + * Encapsulates a CorDapp that exists on the current classpath, which can be pulled in for testing. Use [TestCordapp.findCordapp] * to locate an existing CorDapp. * * @see DriverParameters.cordappsForAllNodes @@ -15,27 +15,25 @@ import net.corda.testing.node.internal.TestCordappImpl * @see MockNodeParameters.additionalCordapps */ @DoNotImplement -interface TestCordapp { +abstract class TestCordapp { /** The package used to find the CorDapp. This may not be the root package of the CorDapp. */ - val scanPackage: String + abstract val scanPackage: String /** Returns the config for on this CorDapp, defaults to empty if not specified. */ - val config: Map + abstract val config: Map /** Returns a copy of this [TestCordapp] but with the specified CorDapp config. */ - fun withConfig(config: Map): TestCordapp + abstract fun withConfig(config: Map): TestCordapp - class Factory { - companion object { - /** - * Scans the current classpath to find the CorDapp that contains the given package. All the CorDapp's metdata present in its - * MANIFEST are inherited. If more than one location containing the package is found then an exception is thrown. An exception - * is also thrown if no CorDapp is found. - * - * @param scanPackage The package name used to find the CorDapp. This does not need to be the root package. - */ - @JvmStatic - fun findCordapp(scanPackage: String): TestCordapp = TestCordappImpl(scanPackage = scanPackage, config = emptyMap()) - } + companion object { + /** + * Scans the current classpath to find the CorDapp that contains the given package. All the CorDapp's metdata present in its + * MANIFEST are inherited. If more than one location containing the package is found then an exception is thrown. An exception + * is also thrown if no CorDapp is found. + * + * @param scanPackage The package name used to find the CorDapp. This does not need to be the root package of the CorDapp. + */ + @JvmStatic + fun findCordapp(scanPackage: String): TestCordapp = TestCordappImpl(scanPackage = scanPackage, config = emptyMap()) } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt index 531714dac5..7b420a566c 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/CustomCordapp.kt @@ -32,7 +32,7 @@ data class CustomCordapp( val classes: Set> = emptySet(), val signingInfo: SigningInfo? = null, override val config: Map = emptyMap() -) : TestCordappInternal { +) : TestCordappInternal() { init { require(packages.isNotEmpty() || classes.isNotEmpty()) { "At least one package or class must be specified" } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappImpl.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappImpl.kt index 0f6e666e02..bc8f199fa4 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappImpl.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappImpl.kt @@ -13,12 +13,12 @@ import kotlin.streams.toList /** * Implementation of the public [TestCordapp] API. * - * As described in [TestCordapp.Factory.findCordapp], this represents a single CorDapp jar on the current classpath. The [scanPackage] may + * As described in [TestCordapp.findCordapp], this represents a single CorDapp jar on the current classpath. The [scanPackage] may * be for an external dependency to the project that's using this API, in which case that dependency jar is referenced as is. On the other hand, * the [scanPackage] may reference a gradle CorDapp project on the local system. In this scenerio the project's "jar" task is executed to * build the CorDapp jar. This allows us to inherit the CorDapp's MANIFEST information without having to do any extra processing. */ -data class TestCordappImpl(override val scanPackage: String, override val config: Map) : TestCordappInternal { +data class TestCordappImpl(override val scanPackage: String, override val config: Map) : TestCordappInternal() { override fun withConfig(config: Map): TestCordappImpl = copy(config = config) override fun withOnlyJarContents(): TestCordappImpl = copy(config = emptyMap()) @@ -27,9 +27,11 @@ data class TestCordappImpl(override val scanPackage: String, override val config get() { val jars = TestCordappImpl.findJars(scanPackage) when (jars.size) { - 0 -> throw IllegalArgumentException("Package $scanPackage does not exist") + 0 -> throw IllegalArgumentException("There are no CorDapps containing the package $scanPackage on the classpath. Make sure " + + "the package name is correct and that the CorDapp is added as a gradle dependency.") 1 -> return jars.first() - else -> throw IllegalArgumentException("More than one jar found containing package $scanPackage: $jars") + else -> throw IllegalArgumentException("There is more than one CorDapp containing the package $scanPackage on the classpath " + + "$jars. Specify a package name which is unique to the CorDapp.") } } diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt index 9c10b63c0c..1a14b28000 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappInternal.kt @@ -14,11 +14,11 @@ import java.nio.file.StandardCopyOption.REPLACE_EXISTING * * @property jarFile The jar file this CorDapp represents. Different CorDapps may point to the same file. */ -interface TestCordappInternal : TestCordapp { - val jarFile: Path +abstract class TestCordappInternal : TestCordapp() { + abstract val jarFile: Path /** Return a copy of this TestCordappInternal but without any metadata, such as configs and signing information. */ - fun withOnlyJarContents(): TestCordappInternal + abstract fun withOnlyJarContents(): TestCordappInternal companion object { fun installCordapps(baseDirectory: Path, diff --git a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappsUtils.kt b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappsUtils.kt index 258760c2b5..6ac1f3c216 100644 --- a/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappsUtils.kt +++ b/testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/TestCordappsUtils.kt @@ -44,9 +44,9 @@ fun cordappForClasses(vararg classes: Class<*>): CustomCordapp = CustomCordapp(p /** * Find the single CorDapp jar on the current classpath which contains the given package. This is a convenience method for - * [TestCordapp.Factory.findCordapp] but returns the internal [TestCordappImpl]. + * [TestCordapp.findCordapp] but returns the internal [TestCordappImpl]. */ -fun findCordapp(scanPackage: String): TestCordappImpl = TestCordapp.Factory.findCordapp(scanPackage) as TestCordappImpl +fun findCordapp(scanPackage: String): TestCordappImpl = TestCordapp.findCordapp(scanPackage) as TestCordappImpl fun getCallerClass(directCallerClass: KClass<*>): Class<*>? { val stackTrace = Throwable().stackTrace diff --git a/testing/node-driver/src/test/kotlin/net/corda/testing/node/MockNetworkTest.kt b/testing/node-driver/src/test/kotlin/net/corda/testing/node/MockNetworkTest.kt index 7287ff4d5d..1e841a2acc 100644 --- a/testing/node-driver/src/test/kotlin/net/corda/testing/node/MockNetworkTest.kt +++ b/testing/node-driver/src/test/kotlin/net/corda/testing/node/MockNetworkTest.kt @@ -16,7 +16,7 @@ class MockNetworkTest { @Before fun setup() { - mockNetwork = MockNetwork() + mockNetwork = MockNetwork(MockNetworkParameters()) } @After