Merge remote-tracking branch 'open/master' into os-merge-68145e1

# Conflicts:
#	node/src/integration-test/kotlin/net/corda/node/flows/FlowOverrideTests.kt
#	testing/node-driver/src/main/kotlin/net/corda/testing/node/internal/DriverDSLImpl.kt
#	tools/explorer/src/main/kotlin/net/corda/explorer/ExplorerSimulation.kt
This commit is contained in:
Shams Asari 2018-11-28 17:10:09 +00:00
commit 73ca1601fb
11 changed files with 264 additions and 383 deletions

View File

@ -149,7 +149,7 @@ abstract class TransactionVerificationException(val txId: SecureHash, message: S
"is not satisfied. Encumbered states should also be referenced as an encumbrance of another state to form " +
"a full cycle. Offending indices $nonMatching", null)
/**HEAD
/**
* All encumbered states should be assigned to the same notary. This is due to the fact that multi-notary
* transactions are not supported and thus two encumbered states with different notaries cannot be consumed
* in the same transaction.

View File

@ -10,6 +10,7 @@ import net.corda.core.utilities.unwrap
import net.corda.testing.core.*
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.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
@ -55,8 +56,14 @@ class AsymmetricCorDappsTests : IntegrationTest() {
@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()
}
}
@ -66,8 +73,10 @@ class AsymmetricCorDappsTests : IntegrationTest() {
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()
}
}
@ -77,8 +86,10 @@ class AsymmetricCorDappsTests : IntegrationTest() {
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

@ -20,6 +20,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.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
@ -119,7 +120,7 @@ class FlowCheckpointVersionNodeStartupCheckTest: IntegrationTest() {
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()
@ -131,12 +132,12 @@ class FlowCheckpointVersionNodeStartupCheckTest: IntegrationTest() {
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

@ -11,13 +11,14 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.DUMMY_NOTARY_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.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.internal.toDatabaseSchemaName
import net.corda.testing.node.internal.cordappForClasses
import org.hamcrest.CoreMatchers.`is`
import org.junit.Assert
import org.junit.Assert.assertThat
import org.junit.ClassRule
import org.junit.Test
@ -41,7 +42,7 @@ class FlowOverrideTests : IntegrationTest() {
@InitiatedBy(Ping::class)
open class Pong(private val pingSession: FlowSession) : FlowLogic<Unit>() {
companion object {
val PONG = "PONG"
const val PONG = "PONG"
}
@Suspendable
@ -62,7 +63,7 @@ class FlowOverrideTests : IntegrationTest() {
class Pongiest(private val pingSession: FlowSession) : Pong(pingSession) {
companion object {
val GORGONZOLA = "Gorgonzola"
const val GORGONZOLA = "Gorgonzola"
}
@Suspendable
@ -71,16 +72,21 @@ class FlowOverrideTests : IntegrationTest() {
}
}
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))
}
}
@ -88,9 +94,16 @@ class FlowOverrideTests : IntegrationTest() {
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

@ -30,6 +30,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.*
import net.corda.testing.node.internal.cordappsForPackages
@ -107,8 +108,9 @@ class AttachmentLoadingTests : IntegrationTest() {
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

@ -33,22 +33,43 @@ import kotlin.reflect.jvm.javaType
* will find it useful to revert to earlier states of knowledge about which types have been visited on a given branch.
*/
internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
val resolutionContext: Type? = null,
val visited: Set<TypeIdentifier> = emptySet(),
val cycles: MutableList<LocalTypeInformation.Cycle> = mutableListOf()) {
var resolutionContext: Type? = null,
var visited: Set<TypeIdentifier> = emptySet(),
val cycles: MutableList<LocalTypeInformation.Cycle> = mutableListOf(),
var warnIfNonComposable: Boolean = true) {
companion object {
private val logger = contextLogger()
}
/**
* If we are examining the type of a read-only property, or a type flagged as [Opaque], then we do not need to warn
* if the [LocalTypeInformation] for that type (or any of its related types) is [LocalTypeInformation.NonComposable].
*/
private inline fun <T> suppressWarningsAnd(block: LocalTypeInformationBuilder.() -> T): T {
val previous = warnIfNonComposable
return try {
warnIfNonComposable = false
block()
} finally {
warnIfNonComposable = previous
}
}
/**
* Recursively build [LocalTypeInformation] for the given [Type] and [TypeIdentifier]
*/
fun build(type: Type, typeIdentifier: TypeIdentifier): LocalTypeInformation =
if (typeIdentifier in visited) LocalTypeInformation.Cycle(type, typeIdentifier).apply { cycles.add(this) }
else lookup.findOrBuild(type, typeIdentifier) { isOpaque ->
copy(visited = visited + typeIdentifier).buildIfNotFound(type, typeIdentifier, isOpaque)
}
if (typeIdentifier in visited) LocalTypeInformation.Cycle(type, typeIdentifier).apply { cycles.add(this) }
else lookup.findOrBuild(type, typeIdentifier) { isOpaque ->
val previous = visited
try {
visited = visited + typeIdentifier
buildIfNotFound(type, typeIdentifier, isOpaque)
} finally {
visited = previous
}
}
private fun resolveAndBuild(type: Type): LocalTypeInformation {
val resolved = type.resolveAgainstContext()
@ -57,7 +78,7 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
}
private fun Type.resolveAgainstContext(): Type =
if (resolutionContext == null) this else resolveAgainst(resolutionContext)
resolutionContext?.let(::resolveAgainst) ?: this
private fun buildIfNotFound(type: Type, typeIdentifier: TypeIdentifier, isOpaque: Boolean): LocalTypeInformation {
val rawType = type.asClass()
@ -79,7 +100,7 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
private fun buildForClass(type: Class<*>, typeIdentifier: TypeIdentifier, isOpaque: Boolean): LocalTypeInformation = withContext(type) {
when {
Collection::class.java.isAssignableFrom(type) &&
!EnumSet::class.java.isAssignableFrom(type) -> LocalTypeInformation.ACollection(type, typeIdentifier, LocalTypeInformation.Unknown)
!EnumSet::class.java.isAssignableFrom(type) -> LocalTypeInformation.ACollection(type, typeIdentifier, LocalTypeInformation.Unknown)
Map::class.java.isAssignableFrom(type) -> LocalTypeInformation.AMap(type, typeIdentifier, LocalTypeInformation.Unknown, LocalTypeInformation.Unknown)
type.kotlin.javaPrimitiveType != null -> LocalTypeInformation.Atomic(type.kotlin.javaPrimitiveType!!, typeIdentifier)
type.isEnum -> LocalTypeInformation.AnEnum(
@ -95,9 +116,12 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
type.isInterface -> buildInterface(type, typeIdentifier, emptyList())
type.isAbstractClass -> buildAbstract(type, typeIdentifier, emptyList())
isOpaque -> LocalTypeInformation.Opaque(
type,
typeIdentifier,
buildNonAtomic(type, type, typeIdentifier, emptyList(), true))
type,
typeIdentifier,
suppressWarningsAnd { buildNonAtomic(type, type, typeIdentifier, emptyList()) })
Exception::class.java.isAssignableFrom(type.asClass()) -> suppressWarningsAnd {
buildNonAtomic(type, type, typeIdentifier, emptyList())
}
else -> buildNonAtomic(type, type, typeIdentifier, emptyList())
}
}
@ -109,7 +133,7 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
isOpaque: Boolean): LocalTypeInformation = withContext(type) {
when {
Collection::class.java.isAssignableFrom(rawType) &&
!EnumSet::class.java.isAssignableFrom(rawType) ->
!EnumSet::class.java.isAssignableFrom(rawType) ->
LocalTypeInformation.ACollection(type, typeIdentifier, buildTypeParameterInformation(type)[0])
Map::class.java.isAssignableFrom(rawType) -> {
val (keyType, valueType) = buildTypeParameterInformation(type)
@ -118,8 +142,8 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
rawType.isInterface -> buildInterface(type, typeIdentifier, buildTypeParameterInformation(type))
rawType.isAbstractClass -> buildAbstract(type, typeIdentifier, buildTypeParameterInformation(type))
isOpaque -> LocalTypeInformation.Opaque(rawType,
typeIdentifier,
buildNonAtomic(rawType, type, typeIdentifier, buildTypeParameterInformation(type), true))
typeIdentifier,
suppressWarningsAnd { buildNonAtomic(rawType, type, typeIdentifier, buildTypeParameterInformation(type)) })
else -> buildNonAtomic(rawType, type, typeIdentifier, buildTypeParameterInformation(type))
}
}
@ -143,8 +167,15 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
buildInterfaceInformation(type),
typeParameters)
private inline fun <T> withContext(newContext: Type, block: LocalTypeInformationBuilder.() -> T): T =
copy(resolutionContext = newContext).run(block)
private inline fun <T> withContext(newContext: Type, block: LocalTypeInformationBuilder.() -> T): T {
val previous = resolutionContext
return try {
resolutionContext = newContext
block()
} finally {
resolutionContext = previous
}
}
/**
* Build a non-atomic type, which is either [Composable] or [NonComposable].
@ -156,13 +187,13 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
* Rather than throwing an exception if a type is [NonComposable], we capture its type information so that it can
* still be used to _serialize_ values, or as the basis for deciding on an evolution strategy.
*/
private fun buildNonAtomic(rawType: Class<*>, type: Type, typeIdentifier: TypeIdentifier, typeParameterInformation: List<LocalTypeInformation>, suppressWarning: Boolean = false): LocalTypeInformation {
private fun buildNonAtomic(rawType: Class<*>, type: Type, typeIdentifier: TypeIdentifier, typeParameterInformation: List<LocalTypeInformation>): LocalTypeInformation {
val superclassInformation = buildSuperclassInformation(type)
val interfaceInformation = buildInterfaceInformation(type)
val observedConstructor = constructorForDeserialization(type)
if (observedConstructor == null) {
if (!suppressWarning) {
if (warnIfNonComposable) {
logger.info("No unique deserialisation constructor found for class $rawType, type is marked as non-composable")
}
return LocalTypeInformation.NonComposable(type, typeIdentifier, null, buildReadOnlyProperties(rawType),
@ -175,7 +206,7 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
val hasNonComposableProperties = properties.values.any { it.type is LocalTypeInformation.NonComposable }
if (!propertiesSatisfyConstructor(constructorInformation, properties) || hasNonComposableProperties) {
if (!suppressWarning) {
if (warnIfNonComposable) {
if (hasNonComposableProperties) {
logger.info("Type ${type.typeName} has non-composable properties and has been marked as non-composable")
} else {
@ -214,7 +245,7 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
}
private fun buildSuperclassInformation(type: Type): LocalTypeInformation =
resolveAndBuild(type.asClass().genericSuperclass)
resolveAndBuild(type.asClass().genericSuperclass)
private fun buildInterfaceInformation(type: Type) =
type.allInterfaces.asSequence().mapNotNull {
@ -244,8 +275,10 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
if (descriptor.field == null || descriptor.getter == null) null
else {
val paramType = (descriptor.getter.genericReturnType).resolveAgainstContext()
val paramTypeInformation = build(paramType, TypeIdentifier.forGenericType(paramType, resolutionContext
?: rawType))
// Because this parameter is read-only, we don't need to warn if its type is non-composable.
val paramTypeInformation = suppressWarningsAnd {
build(paramType, TypeIdentifier.forGenericType(paramType, resolutionContext ?: rawType))
}
val isMandatory = paramType.asClass().isPrimitive || !descriptor.getter.returnsNullable()
name to LocalPropertyInformation.ReadOnlyProperty(descriptor.getter, paramTypeInformation, isMandatory)
}
@ -275,10 +308,10 @@ internal data class LocalTypeInformationBuilder(val lookup: LocalTypeLookup,
name: String,
descriptor: PropertyDescriptor,
constructorInformation: LocalConstructorInformation): LocalPropertyInformation? {
val constructorIndex = constructorParameterIndices[name] ?:
// In some very rare cases we have a constructor parameter matched by a getter with no backing field,
// and cannot infer whether the property name should be capitalised or not.
constructorParameterIndices[name.decapitalize()] ?: return null
// In some very rare cases we have a constructor parameter matched by a getter with no backing field,
// and cannot infer whether the property name should be capitalised or not.
val constructorIndex = constructorParameterIndices[name] ?: constructorParameterIndices[name.decapitalize()]
if (constructorIndex == null) return null
if (descriptor.getter == null) {
if (descriptor.field == null) return null

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.*
@ -25,6 +24,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
@ -40,7 +40,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
@ -49,7 +48,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
@ -196,73 +194,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,
emptyMap(),
null
)
}
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> {
return startNode(
defaultParameters,
providedName,
rpcUsers,
verifierType,
customOverrides,
startInSameProcess,
maximumHeapSize,
additionalCordapps,
regenerateCordappsOnStart,
flowOverrides,
null
)
}
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<*>>>,
bytemanPort: Int?
): 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)
}
@ -270,28 +209,21 @@ 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, bytemanPort)
startRegisteredNode(name, it, parameters, p2pAddress, signCordapps, bytemanPort)
}
}
}
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,
bytemanPort: Int? = null): 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 ->
@ -308,7 +240,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(),
@ -316,17 +249,17 @@ 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,
"enterpriseConfiguration.tuning.flowThreadPoolSize" to "1",
NodeConfiguration::flowOverrides.name to flowOverrideConfig.toConfig().root().unwrapped(),
NodeConfiguration::enableSNI.name to enableSNI
) + 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, bytemanPort)
return startNodeInternal(config, webAddress, localNetworkMap, parameters, signCordapps, bytemanPort)
}
private fun startNodeRegistration(
@ -543,9 +476,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) }
}
@ -571,9 +502,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 {
@ -581,9 +511,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))
)
}
@ -621,11 +549,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,
bytemanPort: Int? = null): CordaFuture<NodeHandle> {
val visibilityHandle = networkVisibilityController.register(specifiedConfig.corda.myLegalName)
@ -640,24 +565,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) ->
@ -684,7 +609,7 @@ class DriverDSLImpl(
return nodeFuture
} else {
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val process = startOutOfProcessNode(config, quasarJarPath, debugPort, bytemanJarPath, bytemanPort, systemProperties, maximumHeapSize)
val process = startOutOfProcessNode(config, quasarJarPath, debugPort, bytemanJarPath, bytemanPort, 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
@ -1269,14 +1194,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

@ -90,16 +90,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"))))
)
))
val bno = startNode(providedName = IOUFlow.allowedMembershipName, rpcUsers = listOf(user))
notaryNode = defaultNotaryNode.get()