CORDA-2239: DriverDSL.startNode overload cleanup (#4252)

The overload that takes in a bunch of the node parameters with default values has been fixed to the V3 version. New node parameters since V3 now only exist in NodeParameters.

The reason for this is otherwise each new release of Corda that introduces new node parameters will force a new startNode overload to be added to DriverDSL to preserve backwards compatibility.

NodeParameters has been moved to its own file and logLevel is removed as it doesn't do anything.
This commit is contained in:
Shams Asari 2018-11-28 14:36:26 +00:00 committed by Michele Sollecito
parent 994afcfef7
commit 36fdb858c6
9 changed files with 203 additions and 328 deletions

View File

@ -11,6 +11,7 @@ import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.NodeParameters
import net.corda.testing.driver.driver
import net.corda.testing.node.internal.cordappForClasses
import org.junit.Test
@ -47,8 +48,14 @@ class AsymmetricCorDappsTests {
@Test
fun `no shared cordapps with asymmetric specific classes`() {
driver(DriverParameters(startNodesInProcess = false, cordappsForAllNodes = emptySet())) {
val nodeA = startNode(providedName = ALICE_NAME, additionalCordapps = setOf(cordappForClasses(Ping::class.java))).getOrThrow()
val nodeB = startNode(providedName = BOB_NAME, additionalCordapps = setOf(cordappForClasses(Ping::class.java, Pong::class.java))).getOrThrow()
val nodeA = startNode(NodeParameters(
providedName = ALICE_NAME,
additionalCordapps = setOf(cordappForClasses(Ping::class.java))
)).getOrThrow()
val nodeB = startNode(NodeParameters(
providedName = BOB_NAME,
additionalCordapps = setOf(cordappForClasses(Ping::class.java, Pong::class.java))
)).getOrThrow()
nodeA.rpc.startFlow(::Ping, nodeB.nodeInfo.singleIdentity(), 1).returnValue.getOrThrow()
}
}
@ -58,8 +65,10 @@ class AsymmetricCorDappsTests {
val sharedCordapp = cordappForClasses(Ping::class.java)
val cordappForNodeB = cordappForClasses(Pong::class.java)
driver(DriverParameters(startNodesInProcess = false, cordappsForAllNodes = setOf(sharedCordapp))) {
val (nodeA, nodeB) = listOf(startNode(providedName = ALICE_NAME), startNode(providedName = BOB_NAME, additionalCordapps = setOf(cordappForNodeB))).transpose().getOrThrow()
val (nodeA, nodeB) = listOf(
startNode(NodeParameters(providedName = ALICE_NAME)),
startNode(NodeParameters(providedName = BOB_NAME, additionalCordapps = setOf(cordappForNodeB)))
).transpose().getOrThrow()
nodeA.rpc.startFlow(::Ping, nodeB.nodeInfo.singleIdentity(), 1).returnValue.getOrThrow()
}
}
@ -69,8 +78,10 @@ class AsymmetricCorDappsTests {
val sharedCordapp = cordappForClasses(Ping::class.java)
val cordappForNodeB = cordappForClasses(Pong::class.java)
driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = setOf(sharedCordapp))) {
val (nodeA, nodeB) = listOf(startNode(providedName = ALICE_NAME), startNode(providedName = BOB_NAME, additionalCordapps = setOf(cordappForNodeB))).transpose().getOrThrow()
val (nodeA, nodeB) = listOf(
startNode(NodeParameters(providedName = ALICE_NAME)),
startNode(NodeParameters(providedName = BOB_NAME, additionalCordapps = setOf(cordappForNodeB)))
).transpose().getOrThrow()
nodeA.rpc.startFlow(::Ping, nodeB.nodeInfo.singleIdentity(), 1).returnValue.getOrThrow()
}
}

View File

@ -15,6 +15,7 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.DriverDSL
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.NodeParameters
import net.corda.testing.driver.driver
import net.corda.testing.node.TestCordapp
import net.corda.testing.node.internal.ListenProcessDeathException
@ -106,7 +107,7 @@ class FlowCheckpointVersionNodeStartupCheckTest {
private fun DriverDSL.createSuspendedFlowInBob(cordapps: Set<TestCordapp>) {
val (alice, bob) = listOf(ALICE_NAME, BOB_NAME)
.map { startNode(providedName = it, additionalCordapps = cordapps) }
.map { startNode(NodeParameters(providedName = it, additionalCordapps = cordapps)) }
.transpose()
.getOrThrow()
alice.stop()
@ -118,12 +119,12 @@ class FlowCheckpointVersionNodeStartupCheckTest {
private fun DriverDSL.assertBobFailsToStartWithLogMessage(cordapps: Collection<TestCordapp>, logMessage: String) {
assertFailsWith(ListenProcessDeathException::class) {
startNode(
startNode(NodeParameters(
providedName = BOB_NAME,
customOverrides = mapOf("devMode" to false),
additionalCordapps = cordapps,
regenerateCordappsOnStart = true
).getOrThrow()
)).getOrThrow()
}
val logDir = baseDirectory(BOB_NAME) / NodeStartup.LOGS_DIRECTORY_NAME

View File

@ -10,10 +10,11 @@ import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.NodeParameters
import net.corda.testing.driver.driver
import net.corda.testing.node.internal.cordappForClasses
import org.hamcrest.CoreMatchers.`is`
import org.junit.Assert
import org.junit.Assert.assertThat
import org.junit.Test
class FlowOverrideTests {
@ -31,7 +32,7 @@ class FlowOverrideTests {
@InitiatedBy(Ping::class)
open class Pong(private val pingSession: FlowSession) : FlowLogic<Unit>() {
companion object {
val PONG = "PONG"
const val PONG = "PONG"
}
@Suspendable
@ -52,7 +53,7 @@ class FlowOverrideTests {
class Pongiest(private val pingSession: FlowSession) : Pong(pingSession) {
companion object {
val GORGONZOLA = "Gorgonzola"
const val GORGONZOLA = "Gorgonzola"
}
@Suspendable
@ -61,16 +62,21 @@ class FlowOverrideTests {
}
}
private val nodeAClasses = setOf(Ping::class.java,
Pong::class.java, Pongiest::class.java)
private val nodeAClasses = setOf(Ping::class.java, Pong::class.java, Pongiest::class.java)
private val nodeBClasses = setOf(Ping::class.java, Pong::class.java)
@Test
fun `should use the most specific implementation of a responding flow`() {
driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = emptySet())) {
val nodeA = startNode(providedName = ALICE_NAME, additionalCordapps = setOf(cordappForClasses(*nodeAClasses.toTypedArray()))).getOrThrow()
val nodeB = startNode(providedName = BOB_NAME, additionalCordapps = setOf(cordappForClasses(*nodeBClasses.toTypedArray()))).getOrThrow()
Assert.assertThat(nodeB.rpc.startFlow(::Ping, nodeA.nodeInfo.singleIdentity()).returnValue.getOrThrow(), `is`(net.corda.node.flows.FlowOverrideTests.Pongiest.GORGONZOLA))
val nodeA = startNode(NodeParameters(
providedName = ALICE_NAME,
additionalCordapps = setOf(cordappForClasses(*nodeAClasses.toTypedArray()))
)).getOrThrow()
val nodeB = startNode(NodeParameters(
providedName = BOB_NAME,
additionalCordapps = setOf(cordappForClasses(*nodeBClasses.toTypedArray()))
)).getOrThrow()
assertThat(nodeB.rpc.startFlow(::Ping, nodeA.nodeInfo.singleIdentity()).returnValue.getOrThrow(), `is`(Pongiest.GORGONZOLA))
}
}
@ -78,9 +84,16 @@ class FlowOverrideTests {
fun `should use the overriden implementation of a responding flow`() {
val flowOverrides = mapOf(Ping::class.java to Pong::class.java)
driver(DriverParameters(startNodesInProcess = true, cordappsForAllNodes = emptySet())) {
val nodeA = startNode(providedName = ALICE_NAME, additionalCordapps = setOf(cordappForClasses(*nodeAClasses.toTypedArray())), flowOverrides = flowOverrides).getOrThrow()
val nodeB = startNode(providedName = BOB_NAME, additionalCordapps = setOf(cordappForClasses(*nodeBClasses.toTypedArray()))).getOrThrow()
Assert.assertThat(nodeB.rpc.startFlow(::Ping, nodeA.nodeInfo.singleIdentity()).returnValue.getOrThrow(), `is`(net.corda.node.flows.FlowOverrideTests.Pong.PONG))
val nodeA = startNode(NodeParameters(
providedName = ALICE_NAME,
additionalCordapps = setOf(cordappForClasses(*nodeAClasses.toTypedArray())),
flowOverrides = flowOverrides
)).getOrThrow()
val nodeB = startNode(NodeParameters(
providedName = BOB_NAME,
additionalCordapps = setOf(cordappForClasses(*nodeBClasses.toTypedArray()))
)).getOrThrow()
assertThat(nodeB.rpc.startFlow(::Ping, nodeA.nodeInfo.singleIdentity()).returnValue.getOrThrow(), `is`(Pong.PONG))
}
}

View File

@ -28,6 +28,7 @@ import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.TestIdentity
import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.NodeParameters
import net.corda.testing.driver.driver
import net.corda.testing.internal.MockCordappConfigProvider
import net.corda.testing.internal.rigorousMock
@ -101,8 +102,9 @@ class AttachmentLoadingTests {
fun `test that attachments retrieved over the network are not used for code`() {
withoutTestSerialization {
driver(DriverParameters(startNodesInProcess = true, notarySpecs = emptyList(), cordappsForAllNodes = emptySet())) {
val bankA = startNode(providedName = bankAName, additionalCordapps = cordappsForPackages("net.corda.finance.contracts.isolated")).getOrThrow()
val bankB = startNode(providedName = bankBName, additionalCordapps = cordappsForPackages("net.corda.finance.contracts.isolated")).getOrThrow()
val additionalCordapps = cordappsForPackages("net.corda.finance.contracts.isolated")
val bankA = startNode(NodeParameters(providedName = bankAName, additionalCordapps = additionalCordapps)).getOrThrow()
val bankB = startNode(NodeParameters(providedName = bankBName, additionalCordapps = additionalCordapps)).getOrThrow()
assertFailsWith<CordaRuntimeException>("Party C=CH,L=Zurich,O=BankB rejected session request: Don't know net.corda.finance.contracts.isolated.IsolatedDummyFlow\$Initiator") {
bankA.rpc.startFlowDynamic(flowInitiatorClass, bankB.nodeInfo.legalIdentities.first()).returnValue.getOrThrow()
}

View File

@ -5,7 +5,6 @@ package net.corda.testing.driver
import net.corda.core.DoNotImplement
import net.corda.core.concurrent.CordaFuture
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NetworkParameters
@ -13,7 +12,6 @@ import net.corda.core.node.NodeInfo
import net.corda.core.node.ServiceHub
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.Node
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.driver.internal.incrementalPortAllocation
@ -122,181 +120,6 @@ abstract class PortAllocation {
}
}
/**
* Helper builder for configuring a [Node] from Java.
*
* @property providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @property rpcUsers List of users who are authorised to use the RPC system. Defaults to a single user with
* all permissions.
* @property verifierType The type of transaction verifier to use. See: [VerifierType]
* @property customOverrides A map of custom node configuration overrides.
* @property startInSameProcess Determines if the node should be started inside the same process the Driver is running
* in. If null the Driver-level value will be used.
* @property maximumHeapSize The maximum JVM heap size to use for the node.
* @property logLevel Logging level threshold.
* @property additionalCordapps Additional [TestCordapp]s that this node will have available, in addition to the ones common to all nodes managed by the [DriverDSL].
* @property regenerateCordappsOnStart Whether existing [TestCordapp]s unique to this node will be re-generated on start. Useful when stopping and restarting the same node.
*/
@Suppress("unused")
data class NodeParameters(
val providedName: CordaX500Name? = null,
val rpcUsers: List<User> = emptyList(),
val verifierType: VerifierType = VerifierType.InMemory,
val customOverrides: Map<String, Any?> = emptyMap(),
val startInSameProcess: Boolean? = null,
val maximumHeapSize: String = "512m",
val logLevel: String? = null,
val additionalCordapps: Collection<TestCordapp> = emptySet(),
val regenerateCordappsOnStart: Boolean = false,
val flowOverrides: Map<Class<out FlowLogic<*>>, Class<out FlowLogic<*>>> = emptyMap()
) {
/**
* Helper builder for configuring a [Node] from Java.
*
* @param providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to a single user with
* all permissions.
* @param verifierType The type of transaction verifier to use. See: [VerifierType]
* @param customOverrides A map of custom node configuration overrides.
* @param startInSameProcess Determines if the node should be started inside the same process the Driver is running
* in. If null the Driver-level value will be used.
* @param maximumHeapSize The maximum JVM heap size to use for the node.
* @param logLevel Logging level threshold.
*/
constructor(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String,
logLevel: String? = null
) : this(
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
logLevel,
additionalCordapps = emptySet(),
regenerateCordappsOnStart = false
)
/**
* Helper builder for configuring a [Node] from Java.
*
* @param providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to a single user with
* all permissions.
* @param verifierType The type of transaction verifier to use. See: [VerifierType]
* @param customOverrides A map of custom node configuration overrides.
* @param startInSameProcess Determines if the node should be started inside the same process the Driver is running
* in. If null the Driver-level value will be used.
* @param maximumHeapSize The maximum JVM heap size to use for the node.
*/
constructor(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String
) : this(
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
null,
additionalCordapps = emptySet(),
regenerateCordappsOnStart = false)
/**
* Helper builder for configuring a [Node] from Java.
*
* @param providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to a single user with
* all permissions.
* @param verifierType The type of transaction verifier to use. See: [VerifierType]
* @param customOverrides A map of custom node configuration overrides.
* @param startInSameProcess Determines if the node should be started inside the same process the Driver is running
* in. If null the Driver-level value will be used.
* @param maximumHeapSize The maximum JVM heap size to use for the node.
* @param additionalCordapps Additional [TestCordapp]s that this node will have available, in addition to the ones common to all nodes managed by the [DriverDSL].
* @param regenerateCordappsOnStart Whether existing [TestCordapp]s unique to this node will be re-generated on start. Useful when stopping and restarting the same node.
*/
constructor(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String,
additionalCordapps: Set<TestCordapp> = emptySet(),
regenerateCordappsOnStart: Boolean = false
) : this(
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
null,
additionalCordapps,
regenerateCordappsOnStart)
fun copy(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String
) = this.copy(
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
null)
fun copy(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String,
logLevel: String?
) = this.copy(
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
logLevel,
additionalCordapps = additionalCordapps,
regenerateCordappsOnStart = regenerateCordappsOnStart)
fun withProvidedName(providedName: CordaX500Name?): NodeParameters = copy(providedName = providedName)
fun withRpcUsers(rpcUsers: List<User>): NodeParameters = copy(rpcUsers = rpcUsers)
fun withVerifierType(verifierType: VerifierType): NodeParameters = copy(verifierType = verifierType)
fun withCustomOverrides(customOverrides: Map<String, Any?>): NodeParameters = copy(customOverrides = customOverrides)
fun withStartInSameProcess(startInSameProcess: Boolean?): NodeParameters = copy(startInSameProcess = startInSameProcess)
fun withMaximumHeapSize(maximumHeapSize: String): NodeParameters = copy(maximumHeapSize = maximumHeapSize)
fun withLogLevel(logLevel: String?): NodeParameters = copy(logLevel = logLevel)
fun withAdditionalCordapps(additionalCordapps: Set<TestCordapp>): NodeParameters = copy(additionalCordapps = additionalCordapps)
fun withDeleteExistingCordappsDirectory(regenerateCordappsOnStart: Boolean): NodeParameters = copy(regenerateCordappsOnStart = regenerateCordappsOnStart)
}
/**
* [driver] allows one to start up nodes like this:
* driver {

View File

@ -2,14 +2,11 @@ package net.corda.testing.driver
import net.corda.core.DoNotImplement
import net.corda.core.concurrent.CordaFuture
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.concurrent.map
import net.corda.node.internal.Node
import net.corda.testing.node.TestCordapp
import net.corda.testing.node.User
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.User
import java.nio.file.Path
enum class VerifierType {
@ -56,11 +53,32 @@ interface DriverDSL {
}
}
/**
* Start a node using the default values of [NodeParameters].
*
* @return A [CordaFuture] on the [NodeHandle] to the node. The future will complete when the node is available and
* it sees all previously started nodes, including the notaries.
*/
fun startNode(): CordaFuture<NodeHandle> = startNode(NodeParameters())
/**
* Start a node using the parameter values of the given [NodeParameters].
*
* @param parameters The node parameters.
*
* @return A [CordaFuture] on the [NodeHandle] to the node. The future will complete when the node is available and
* it sees all previously started nodes, including the notaries.
*/
fun startNode(parameters: NodeParameters): CordaFuture<NodeHandle>
/**
* Start a node.
*
* @param defaultParameters The default parameters for the node. Allows the node to be configured in builder style
* when called from Java code.
* NOTE: This method does not provide all the node parameters that are available and only exists for backwards compatibility. It is
* recommended you use [NodeParameters].
*
* @param defaultParameters The default parameters for the node. If any of the remaining parameters to this method are specified then
* their values are taken instead of the corresponding value in [defaultParameters].
* @param providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to empty list.
@ -82,48 +100,16 @@ interface DriverDSL {
customOverrides: Map<String, Any?> = defaultParameters.customOverrides,
startInSameProcess: Boolean? = defaultParameters.startInSameProcess,
maximumHeapSize: String = defaultParameters.maximumHeapSize
): CordaFuture<NodeHandle>
/**
* Start a node.
*
* @param defaultParameters The default parameters for the node. Allows the node to be configured in builder style
* when called from Java code.
* @param providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @param rpcUsers List of users who are authorised to use the RPC system. Defaults to empty list.
* @param verifierType The type of transaction verifier to use. See: [VerifierType].
* @param customOverrides A map of custom node configuration overrides.
* @param startInSameProcess Determines if the node should be started inside the same process the Driver is running
* in. If null the Driver-level value will be used.
* @param maximumHeapSize The maximum JVM heap size to use for the node as a [String]. By default a number is interpreted
* as being in bytes. Append the letter 'k' or 'K' to the value to indicate Kilobytes, 'm' or 'M' to indicate
* megabytes, and 'g' or 'G' to indicate gigabytes. The default value is "512m" = 512 megabytes.
* @param additionalCordapps Additional [TestCordapp]s that this node will have available, in addition to the ones common to all nodes managed by the [DriverDSL].
* @param regenerateCordappsOnStart Whether existing [TestCordapp]s unique to this node will be re-generated on start. Useful when stopping and restarting the same node.
* @return A [CordaFuture] on the [NodeHandle] to the node. The future will complete when the node is available and
* it sees all previously started nodes, including the notaries.
*/
fun startNode(
defaultParameters: NodeParameters = NodeParameters(),
providedName: CordaX500Name? = defaultParameters.providedName,
rpcUsers: List<User> = defaultParameters.rpcUsers,
verifierType: VerifierType = defaultParameters.verifierType,
customOverrides: Map<String, Any?> = defaultParameters.customOverrides,
startInSameProcess: Boolean? = defaultParameters.startInSameProcess,
maximumHeapSize: String = defaultParameters.maximumHeapSize,
additionalCordapps: Collection<TestCordapp> = defaultParameters.additionalCordapps,
regenerateCordappsOnStart: Boolean = defaultParameters.regenerateCordappsOnStart,
flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>> = defaultParameters.flowOverrides
): CordaFuture<NodeHandle>
/**
* Helper function for starting a [Node] with custom parameters from Java.
*
* @param parameters The default parameters for the driver.
* @return [NodeHandle] that will be available sometime in the future.
*/
fun startNode(parameters: NodeParameters): CordaFuture<NodeHandle> = startNode(defaultParameters = parameters)
): CordaFuture<NodeHandle> {
return startNode(defaultParameters.copy(
providedName = providedName,
rpcUsers = rpcUsers,
verifierType = verifierType,
customOverrides = customOverrides,
startInSameProcess = startInSameProcess,
maximumHeapSize = maximumHeapSize
))
}
/** Call [startWebserver] with a default maximumHeapSize. */
@Suppress("DEPRECATION")

View File

@ -0,0 +1,86 @@
package net.corda.testing.driver
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.testing.node.TestCordapp
import net.corda.testing.node.User
/**
* Parameters for creating a node for [DriverDSL.startNode].
*
* @property providedName Optional name of the node, which will be its legal name in [Party]. Defaults to something
* random. Note that this must be unique as the driver uses it as a primary key!
* @property rpcUsers List of users who are authorised to use the RPC system. Defaults to a single user with
* all permissions.
* @property verifierType The type of transaction verifier to use. See: [VerifierType]
* @property customOverrides A map of custom node configuration overrides.
* @property startInSameProcess Determines if the node should be started inside the same process the Driver is running
* in. If null the Driver-level value will be used.
* @property maximumHeapSize The maximum JVM heap size to use for the node. Defaults to 512 MB.
* @property additionalCordapps Additional [TestCordapp]s that this node will have available, in addition to the ones common to all nodes
* managed by the [DriverDSL].
* @property regenerateCordappsOnStart Whether existing [TestCordapp]s unique to this node will be re-generated on start. Useful when stopping
* and restarting the same node.
*/
@Suppress("unused")
data class NodeParameters(
val providedName: CordaX500Name? = null,
val rpcUsers: List<User> = emptyList(),
val verifierType: VerifierType = VerifierType.InMemory,
val customOverrides: Map<String, Any?> = emptyMap(),
val startInSameProcess: Boolean? = null,
val maximumHeapSize: String = "512m",
val additionalCordapps: Collection<TestCordapp> = emptySet(),
val regenerateCordappsOnStart: Boolean = false,
val flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>> = emptyMap()
) {
/**
* Create a new node parameters object with default values. Each parameter can be specified with its wither method which returns a copy
* with that value.
*/
constructor() : this(providedName = null)
fun withProvidedName(providedName: CordaX500Name?): NodeParameters = copy(providedName = providedName)
fun withRpcUsers(rpcUsers: List<User>): NodeParameters = copy(rpcUsers = rpcUsers)
fun withVerifierType(verifierType: VerifierType): NodeParameters = copy(verifierType = verifierType)
fun withCustomOverrides(customOverrides: Map<String, Any?>): NodeParameters = copy(customOverrides = customOverrides)
fun withStartInSameProcess(startInSameProcess: Boolean?): NodeParameters = copy(startInSameProcess = startInSameProcess)
fun withMaximumHeapSize(maximumHeapSize: String): NodeParameters = copy(maximumHeapSize = maximumHeapSize)
fun withAdditionalCordapps(additionalCordapps: Set<TestCordapp>): NodeParameters = copy(additionalCordapps = additionalCordapps)
fun withRegenerateCordappsOnStart(regenerateCordappsOnStart: Boolean): NodeParameters = copy(regenerateCordappsOnStart = regenerateCordappsOnStart)
fun withFlowOverrides(flowOverrides: Map<Class<out FlowLogic<*>>, Class<out FlowLogic<*>>>): NodeParameters = copy(flowOverrides = flowOverrides)
constructor(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String
) : this(
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
additionalCordapps = emptySet())
fun copy(
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String
) = this.copy(
providedName = providedName,
rpcUsers = rpcUsers,
verifierType = verifierType,
customOverrides = customOverrides,
startInSameProcess = startInSameProcess,
maximumHeapSize = maximumHeapSize,
additionalCordapps = additionalCordapps
)
}

View File

@ -9,7 +9,6 @@ import net.corda.client.rpc.internal.createCordaRPCClientWithSslAndClassLoader
import net.corda.cliutils.CommonCliConstants.BASE_DIR
import net.corda.core.concurrent.CordaFuture
import net.corda.core.concurrent.firstOf
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.*
import net.corda.core.internal.concurrent.*
@ -28,6 +27,7 @@ import net.corda.node.internal.NodeWithInfo
import net.corda.node.internal.clientSslOptionsCompatibleWith
import net.corda.node.services.Permissions
import net.corda.node.services.config.*
import net.corda.node.services.config.NodeConfiguration.Companion.cordappDirectoriesKey
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
import net.corda.node.utilities.registration.NodeRegistrationHelper
import net.corda.nodeapi.internal.DevIdentityGenerator
@ -43,7 +43,6 @@ import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.driver.*
import net.corda.testing.driver.VerifierType
import net.corda.testing.driver.internal.InProcessImpl
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.driver.internal.OutOfProcessImpl
@ -52,7 +51,6 @@ import net.corda.testing.internal.stubs.CertificateStoreStubs
import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.TestCordapp
import net.corda.testing.node.User
import net.corda.testing.node.internal.DriverDSLImpl.Companion.cordappsInCurrentAndAdditionalPackages
import okhttp3.OkHttpClient
import okhttp3.Request
@ -186,46 +184,14 @@ class DriverDSLImpl(
}
}
override fun startNode(defaultParameters: NodeParameters,
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String): CordaFuture<NodeHandle> {
return startNode(
defaultParameters,
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
defaultParameters.additionalCordapps,
defaultParameters.regenerateCordappsOnStart
)
}
override fun startNode(
defaultParameters: NodeParameters,
providedName: CordaX500Name?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean?,
maximumHeapSize: String,
additionalCordapps: Collection<TestCordapp>,
regenerateCordappsOnStart: Boolean,
flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>>
): CordaFuture<NodeHandle> {
override fun startNode(parameters: NodeParameters): CordaFuture<NodeHandle> {
val p2pAddress = portAllocation.nextHostAndPort()
// TODO: Derive name from the full picked name, don't just wrap the common name
val name = providedName
?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB")
val name = parameters.providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB")
val registrationFuture = if (compatibilityZone?.rootCert != null) {
// We don't need the network map to be available to be able to register the node
startNodeRegistration(name, compatibilityZone.rootCert, compatibilityZone.config(), customOverrides)
startNodeRegistration(name, compatibilityZone.rootCert, compatibilityZone.config(), parameters.customOverrides)
} else {
doneFuture(Unit)
}
@ -233,27 +199,20 @@ class DriverDSLImpl(
return registrationFuture.flatMap {
networkMapAvailability.flatMap {
// But starting the node proper does require the network map
startRegisteredNode(name, it, rpcUsers, verifierType, customOverrides, startInSameProcess, maximumHeapSize, p2pAddress, additionalCordapps, regenerateCordappsOnStart, flowOverrides, signCordapps)
startRegisteredNode(name, it, parameters, p2pAddress, signCordapps)
}
}
}
private fun startRegisteredNode(name: CordaX500Name,
localNetworkMap: LocalNetworkMap?,
rpcUsers: List<User>,
verifierType: VerifierType,
customOverrides: Map<String, Any?>,
startInSameProcess: Boolean? = null,
maximumHeapSize: String = "512m",
parameters: NodeParameters,
p2pAddress: NetworkHostAndPort = portAllocation.nextHostAndPort(),
additionalCordapps: Collection<TestCordapp> = emptySet(),
regenerateCordappsOnStart: Boolean = false,
flowOverrides: Map<out Class<out FlowLogic<*>>, Class<out FlowLogic<*>>> = emptyMap(),
signCordapps: Boolean = false): CordaFuture<NodeHandle> {
val rpcAddress = portAllocation.nextHostAndPort()
val rpcAdminAddress = portAllocation.nextHostAndPort()
val webAddress = portAllocation.nextHostAndPort()
val users = rpcUsers.map { it.copy(permissions = it.permissions + DRIVER_REQUIRED_PERMISSIONS) }
val users = parameters.rpcUsers.map { it.copy(permissions = it.permissions + DRIVER_REQUIRED_PERMISSIONS) }
val czUrlConfig = when (compatibilityZone) {
null -> emptyMap()
is SharedCompatibilityZoneParams ->
@ -270,7 +229,8 @@ class DriverDSLImpl(
emptyMap()
}
val flowOverrideConfig = FlowOverrideConfig(flowOverrides.entries.map { FlowOverride(it.key.canonicalName, it.value.canonicalName) })
val flowOverrideConfig = FlowOverrideConfig(parameters.flowOverrides.map { FlowOverride(it.key.canonicalName, it.value.canonicalName) })
val overrides = configOf(
NodeConfiguration::myLegalName.name to name.toString(),
NodeConfiguration::p2pAddress.name to p2pAddress.toString(),
@ -278,15 +238,15 @@ class DriverDSLImpl(
"rpcSettings.adminAddress" to rpcAdminAddress.toString(),
NodeConfiguration::useTestClock.name to useTestClock,
NodeConfiguration::rpcUsers.name to if (users.isEmpty()) defaultRpcUserList else users.map { it.toConfig().root().unwrapped() },
NodeConfiguration::verifierType.name to verifierType.name,
NodeConfiguration::verifierType.name to parameters.verifierType.name,
NodeConfiguration::flowOverrides.name to flowOverrideConfig.toConfig().root().unwrapped()
) + czUrlConfig + jmxConfig + customOverrides
) + czUrlConfig + jmxConfig + parameters.customOverrides
val config = NodeConfig(ConfigHelper.loadConfig(
baseDirectory = baseDirectory(name),
allowMissingConfig = true,
configOverrides = if (overrides.hasPath("devMode")) overrides else overrides + mapOf("devMode" to true)
)).checkAndOverrideForInMemoryDB()
return startNodeInternal(config, webAddress, startInSameProcess, maximumHeapSize, localNetworkMap, additionalCordapps, regenerateCordappsOnStart, signCordapps)
return startNodeInternal(config, webAddress, localNetworkMap, parameters, signCordapps)
}
private fun startNodeRegistration(
@ -503,9 +463,7 @@ class DriverDSLImpl(
return startRegisteredNode(
spec.name,
localNetworkMap,
spec.rpcUsers,
spec.verifierType,
customOverrides = notaryConfig + customOverrides
NodeParameters(rpcUsers = spec.rpcUsers, verifierType = spec.verifierType, customOverrides = notaryConfig + customOverrides)
).map { listOf(it) }
}
@ -531,9 +489,8 @@ class DriverDSLImpl(
val firstNodeFuture = startRegisteredNode(
nodeNames[0],
localNetworkMap,
spec.rpcUsers,
spec.verifierType,
customOverrides = notaryConfig(clusterAddress))
NodeParameters(rpcUsers = spec.rpcUsers, verifierType = spec.verifierType, customOverrides = notaryConfig(clusterAddress))
)
// All other nodes will join the cluster
val restNodeFutures = nodeNames.drop(1).map {
@ -541,9 +498,7 @@ class DriverDSLImpl(
startRegisteredNode(
it,
localNetworkMap,
spec.rpcUsers,
spec.verifierType,
customOverrides = notaryConfig(nodeAddress, clusterAddress)
NodeParameters(rpcUsers = spec.rpcUsers, verifierType = spec.verifierType, customOverrides = notaryConfig(nodeAddress, clusterAddress))
)
}
@ -579,11 +534,8 @@ class DriverDSLImpl(
private fun startNodeInternal(specifiedConfig: NodeConfig,
webAddress: NetworkHostAndPort,
startInProcess: Boolean?,
maximumHeapSize: String,
localNetworkMap: LocalNetworkMap?,
additionalCordapps: Collection<TestCordapp>,
regenerateCordappsOnStart: Boolean = false,
parameters: NodeParameters,
signCordapps: Boolean = false): CordaFuture<NodeHandle> {
val visibilityHandle = networkVisibilityController.register(specifiedConfig.corda.myLegalName)
val baseDirectory = specifiedConfig.corda.baseDirectory.createDirectories()
@ -597,24 +549,24 @@ class DriverDSLImpl(
val useHTTPS = specifiedConfig.typesafe.run { hasPath("useHTTPS") && getBoolean("useHTTPS") }
val existingCorDappDirectoriesOption = if (regenerateCordappsOnStart) {
val existingCorDappDirectories = if (parameters.regenerateCordappsOnStart) {
emptyList()
} else if (specifiedConfig.typesafe.hasPath(NodeConfiguration.cordappDirectoriesKey)) {
specifiedConfig.typesafe.getStringList(NodeConfiguration.cordappDirectoriesKey)
} else if (specifiedConfig.typesafe.hasPath(cordappDirectoriesKey)) {
specifiedConfig.typesafe.getStringList(cordappDirectoriesKey)
} else {
emptyList()
}
// Instead of using cordappsForAllNodes we get only these that are missing from additionalCordapps
// This way we prevent errors when we want the same CordApp but with different config
val appOverrides = additionalCordapps.map { it.name to it.version}.toSet()
val appOverrides = parameters.additionalCordapps.map { it.name to it.version }.toSet()
val baseCordapps = cordappsForAllNodes.filter { !appOverrides.contains(it.name to it.version) }
val cordappDirectories = existingCorDappDirectoriesOption + (baseCordapps + additionalCordapps).map { TestCordappDirectories.getJarDirectory(it, signJar = signCordapps).toString() }
val cordappDirectories = existingCorDappDirectories + (baseCordapps + parameters.additionalCordapps).map { TestCordappDirectories.getJarDirectory(it, signJar = signCordapps).toString() }
val config = NodeConfig(specifiedConfig.typesafe.withValue(NodeConfiguration.cordappDirectoriesKey, ConfigValueFactory.fromIterable(cordappDirectories.toSet())))
val config = NodeConfig(specifiedConfig.typesafe.withValue(cordappDirectoriesKey, ConfigValueFactory.fromIterable(cordappDirectories.toSet())))
if (startInProcess ?: startNodesInProcess) {
if (parameters.startInSameProcess ?: startNodesInProcess) {
val nodeAndThreadFuture = startInProcessNode(executorService, config)
shutdownManager.registerShutdown(
nodeAndThreadFuture.map { (node, thread) ->
@ -641,7 +593,7 @@ class DriverDSLImpl(
return nodeFuture
} else {
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val process = startOutOfProcessNode(config, quasarJarPath, debugPort, systemProperties, maximumHeapSize)
val process = startOutOfProcessNode(config, quasarJarPath, debugPort, systemProperties, parameters.maximumHeapSize)
// Destroy the child process when the parent exits.This is needed even when `waitForAllNodesToFinish` is
// true because we don't want orphaned processes in the case that the parent process is terminated by the
@ -1193,14 +1145,15 @@ internal fun DriverParameters.cordappsForAllNodes(): Collection<TestCordapp> = c
?: cordappsInCurrentAndAdditionalPackages(extraCordappPackagesToScan)
fun DriverDSL.startNode(providedName: CordaX500Name, devMode: Boolean, parameters: NodeParameters = NodeParameters()): CordaFuture<NodeHandle> {
var customOverrides = emptyMap<String, String>()
if (!devMode) {
val customOverrides = if (!devMode) {
val nodeDir = baseDirectory(providedName)
val certificatesDirectory = nodeDir / "certificates"
val signingCertStore = CertificateStoreStubs.Signing.withCertificatesDirectory(certificatesDirectory)
val p2pSslConfig = CertificateStoreStubs.P2P.withCertificatesDirectory(certificatesDirectory)
p2pSslConfig.configureDevKeyAndTrustStores(providedName, signingCertStore, certificatesDirectory)
customOverrides = mapOf("devMode" to "false")
parameters.customOverrides + mapOf("devMode" to "false")
} else {
parameters.customOverrides
}
return startNode(parameters, providedName = providedName, customOverrides = customOverrides)
return startNode(parameters.copy(providedName = providedName, customOverrides = customOverrides))
}

View File

@ -80,16 +80,16 @@ class ExplorerSimulation(private val options: OptionSet) {
val bob = startNode(providedName = BOB_NAME, rpcUsers = listOf(user))
val ukBankName = CordaX500Name(organisation = "UK Bank Plc", locality = "London", country = "GB")
val usaBankName = CordaX500Name(organisation = "USA Bank Corp", locality = "New York", country = "US")
val issuerGBP = startNode(
val issuerGBP = startNode(NodeParameters(
providedName = ukBankName,
rpcUsers = listOf(manager),
additionalCordapps = listOf(FINANCE_CORDAPP.withConfig(mapOf("issuableCurrencies" to listOf("GBP"))))
)
val issuerUSD = startNode(
))
val issuerUSD = startNode(NodeParameters(
providedName = usaBankName,
rpcUsers = listOf(manager),
additionalCordapps = listOf(FINANCE_CORDAPP.withConfig(mapOf("issuableCurrencies" to listOf("USD"))))
)
))
notaryNode = defaultNotaryNode.get()
aliceNode = alice.get()