Introduce MockNodeParameters/Args (#1923)

This commit is contained in:
Andrzej Cichocki
2017-10-24 11:58:32 +01:00
committed by GitHub
parent 7f6608deb5
commit 927924498b
13 changed files with 134 additions and 221 deletions

View File

@ -9,21 +9,19 @@ import net.corda.core.internal.FetchAttachmentsFlow
import net.corda.core.internal.FetchDataFlow import net.corda.core.internal.FetchDataFlow
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.ALICE import net.corda.testing.ALICE
import net.corda.testing.ALICE_NAME import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB import net.corda.testing.BOB
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeArgs
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.singleIdentity import net.corda.testing.singleIdentity
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.math.BigInteger
import java.security.KeyPair
import java.util.jar.JarOutputStream import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -113,17 +111,14 @@ class AttachmentTests {
@Test @Test
fun `malicious response`() { fun `malicious response`() {
// Make a node that doesn't do sanity checking at load time. // Make a node that doesn't do sanity checking at load time.
val aliceNode = mockNet.createNotaryNode(legalName = ALICE.name, nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> { val aliceNode = mockNet.createNotaryNode(MockNodeParameters(legalName = ALICE.name), nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
override fun create(config: NodeConfiguration, network: MockNetwork, override fun create(args: MockNodeArgs): MockNetwork.MockNode {
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, return object : MockNetwork.MockNode(args) {
entropyRoot: BigInteger): MockNetwork.MockNode {
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false } override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false }
} }
} }
}, validating = false) }, validating = false)
val bobNode = mockNet.createNode(legalName = BOB.name) val bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB.name))
mockNet.runNetwork() mockNet.runNetwork()
val alice = aliceNode.services.myInfo.identityFromX500Name(ALICE_NAME) val alice = aliceNode.services.myInfo.identityFromX500Name(ALICE_NAME)

View File

@ -13,19 +13,17 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.node.utilities.currentDBSession import net.corda.node.utilities.currentDBSession
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.chooseIdentity import net.corda.testing.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeArgs
import net.corda.testing.node.MockNodeParameters
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.math.BigInteger
import java.nio.charset.StandardCharsets.UTF_8 import java.nio.charset.StandardCharsets.UTF_8
import java.security.KeyPair
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream import java.util.zip.ZipOutputStream
import kotlin.test.assertEquals import kotlin.test.assertEquals
@ -158,10 +156,9 @@ class AttachmentSerializationTest {
private fun rebootClientAndGetAttachmentContent(checkAttachmentsOnLoad: Boolean = true): String { private fun rebootClientAndGetAttachmentContent(checkAttachmentsOnLoad: Boolean = true): String {
client.dispose() client.dispose()
client = mockNet.createNode(client.internals.id, object : MockNetwork.Factory<MockNetwork.MockNode> { client = mockNet.createNode(MockNodeParameters(client.internals.id), object : MockNetwork.Factory<MockNetwork.MockNode> {
override fun create(config: NodeConfiguration, network: MockNetwork, override fun create(args: MockNodeArgs): MockNetwork.MockNode {
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): MockNetwork.MockNode { return object : MockNetwork.MockNode(args) {
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = checkAttachmentsOnLoad } override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = checkAttachmentsOnLoad }
} }
} }

View File

@ -8,6 +8,7 @@ import net.corda.finance.flows.CashPaymentFlow
import net.corda.finance.schemas.CashSchemaV1 import net.corda.finance.schemas.CashSchemaV1
import net.corda.testing.chooseIdentity import net.corda.testing.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test import org.junit.Test
@ -19,12 +20,10 @@ class CashSelectionH2Test {
val mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName)) val mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.finance.contracts.asset", CashSchemaV1::class.packageName))
try { try {
val notaryNode = mockNet.createNotaryNode() val notaryNode = mockNet.createNotaryNode()
val bankA = mockNet.createNode(configOverrides = { existingConfig -> val bankA = mockNet.createNode(MockNodeParameters(configOverrides = { existingConfig ->
// Tweak connections to be minimal to make this easier (1 results in a hung node during start up, so use 2 connections). // Tweak connections to be minimal to make this easier (1 results in a hung node during start up, so use 2 connections).
existingConfig.dataSourceProperties.setProperty("maximumPoolSize", "2") existingConfig.dataSourceProperties.setProperty("maximumPoolSize", "2")
existingConfig }))
})
mockNet.startNodes() mockNet.startNodes()
// Start more cash spends than we have connections. If spend leaks a connection on retry, we will run out of connections. // Start more cash spends than we have connections. If spend leaks a connection on retry, we will run out of connections.

View File

@ -30,6 +30,7 @@ import net.corda.testing.contracts.DummyContract
import net.corda.testing.dummyCommand import net.corda.testing.dummyCommand
import net.corda.testing.getDefaultNotary import net.corda.testing.getDefaultNotary
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test
import java.nio.file.Paths import java.nio.file.Paths
@ -57,10 +58,10 @@ class BFTNotaryServiceTests {
clusterName) clusterName)
val clusterAddresses = replicaIds.map { NetworkHostAndPort("localhost", 11000 + it * 10) } val clusterAddresses = replicaIds.map { NetworkHostAndPort("localhost", 11000 + it * 10) }
replicaIds.forEach { replicaId -> replicaIds.forEach { replicaId ->
mockNet.createNode(configOverrides = { mockNet.createNode(MockNodeParameters(configOverrides = {
val notary = NotaryConfig(validating = false, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses, exposeRaces = exposeRaces)) val notary = NotaryConfig(validating = false, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses, exposeRaces = exposeRaces))
doReturn(notary).whenever(it).notary doReturn(notary).whenever(it).notary
}) }))
} }
mockNet.runNetwork() // Exchange initial network map registration messages. mockNet.runNetwork() // Exchange initial network map registration messages.
} }

View File

@ -34,17 +34,12 @@ import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
import net.corda.finance.flows.TwoPartyTradeFlow.Seller import net.corda.finance.flows.TwoPartyTradeFlow.Seller
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.api.WritableTransactionStorage import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.persistence.DBTransactionStorage import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.node.services.persistence.checkpoints import net.corda.node.services.persistence.checkpoints
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash import net.corda.testing.contracts.fillWithSomeTestCash
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.*
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockServices
import net.corda.testing.node.pumpReceive
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -54,8 +49,6 @@ import org.junit.runners.Parameterized
import rx.Observable import rx.Observable
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.math.BigInteger
import java.security.KeyPair
import java.util.* import java.util.*
import java.util.jar.JarOutputStream import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
@ -267,13 +260,7 @@ class TwoPartyTradeFlowTests(val anonymous: Boolean) {
// ... bring the node back up ... the act of constructing the SMM will re-register the message handlers // ... bring the node back up ... the act of constructing the SMM will re-register the message handlers
// that Bob was waiting on before the reboot occurred. // that Bob was waiting on before the reboot occurred.
bobNode = mockNet.createNode(bobAddr.id, object : MockNetwork.Factory<MockNetwork.MockNode> { bobNode = mockNet.createNode(MockNodeParameters(bobAddr.id, BOB_NAME))
override fun create(config: NodeConfiguration, network: MockNetwork,
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): MockNetwork.MockNode {
return MockNetwork.MockNode(config, network, bobAddr.id, notaryIdentity, entropyRoot)
}
}, BOB_NAME)
// Find the future representing the result of this state machine again. // Find the future representing the result of this state machine again.
val bobFuture = bobNode.smm.findStateMachines(BuyerAcceptor::class.java).single().second val bobFuture = bobNode.smm.findStateMachines(BuyerAcceptor::class.java).single().second
@ -307,19 +294,16 @@ class TwoPartyTradeFlowTests(val anonymous: Boolean) {
// of gets and puts. // of gets and puts.
private fun makeNodeWithTracking(name: CordaX500Name): StartedNode<MockNetwork.MockNode> { private fun makeNodeWithTracking(name: CordaX500Name): StartedNode<MockNetwork.MockNode> {
// Create a node in the mock network ... // Create a node in the mock network ...
return mockNet.createNode(nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> { return mockNet.createNode(MockNodeParameters(legalName = name), nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
override fun create(config: NodeConfiguration, override fun create(args: MockNodeArgs): MockNetwork.MockNode {
network: MockNetwork, return object : MockNetwork.MockNode(args) {
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?,
entropyRoot: BigInteger): MockNetwork.MockNode {
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) {
// That constructs a recording tx storage // That constructs a recording tx storage
override fun makeTransactionStorage(): WritableTransactionStorage { override fun makeTransactionStorage(): WritableTransactionStorage {
return RecordingTransactionStorage(database, super.makeTransactionStorage()) return RecordingTransactionStorage(database, super.makeTransactionStorage())
} }
} }
} }
}, legalName = name) })
} }
@Test @Test

View File

@ -5,6 +5,7 @@ import net.corda.testing.ALICE
import net.corda.testing.BOB import net.corda.testing.BOB
import net.corda.testing.chooseIdentity import net.corda.testing.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test
@ -22,12 +23,12 @@ class NetworkMapCacheTest {
@Test @Test
fun `key collision`() { fun `key collision`() {
val entropy = BigInteger.valueOf(24012017L) val entropy = BigInteger.valueOf(24012017L)
val aliceNode = mockNet.createNode(nodeFactory = MockNetwork.DefaultFactory, legalName = ALICE.name, entropyRoot = entropy) val aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE.name, entropyRoot = entropy))
mockNet.runNetwork() mockNet.runNetwork()
// Node A currently knows only about itself, so this returns node A // Node A currently knows only about itself, so this returns node A
assertEquals(aliceNode.services.networkMapCache.getNodesByLegalIdentityKey(aliceNode.info.chooseIdentity().owningKey).singleOrNull(), aliceNode.info) assertEquals(aliceNode.services.networkMapCache.getNodesByLegalIdentityKey(aliceNode.info.chooseIdentity().owningKey).singleOrNull(), aliceNode.info)
val bobNode = mockNet.createNode(nodeFactory = MockNetwork.DefaultFactory, legalName = BOB.name, entropyRoot = entropy) val bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB.name, entropyRoot = entropy))
assertEquals(aliceNode.info.chooseIdentity(), bobNode.info.chooseIdentity()) assertEquals(aliceNode.info.chooseIdentity(), bobNode.info.chooseIdentity())
aliceNode.services.networkMapCache.addNode(bobNode.info) aliceNode.services.networkMapCache.addNode(bobNode.info)

View File

@ -33,6 +33,7 @@ import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode import net.corda.testing.node.MockNetwork.MockNode
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.pumpReceive import net.corda.testing.node.pumpReceive
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
@ -72,9 +73,8 @@ class FlowFrameworkTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts", "net.corda.testing.contracts")) mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts", "net.corda.testing.contracts"))
aliceNode = mockNet.createNode(legalName = ALICE_NAME) aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
bobNode = mockNet.createNode(legalName = BOB_NAME) bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
mockNet.runNetwork() mockNet.runNetwork()
// We intentionally create our own notary and ignore the one provided by the network // We intentionally create our own notary and ignore the one provided by the network
@ -176,8 +176,7 @@ class FlowFrameworkTests {
var sentCount = 0 var sentCount = 0
mockNet.messagingNetwork.sentMessages.toSessionTransfers().filter { it.isPayloadTransfer }.forEach { sentCount++ } mockNet.messagingNetwork.sentMessages.toSessionTransfers().filter { it.isPayloadTransfer }.forEach { sentCount++ }
val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME)
val secondFlow = charlieNode.registerFlowFactory(PingPongFlow::class) { PingPongFlow(it, payload2) } val secondFlow = charlieNode.registerFlowFactory(PingPongFlow::class) { PingPongFlow(it, payload2) }
mockNet.runNetwork() mockNet.runNetwork()
val charlie = charlieNode.info.singleIdentity() val charlie = charlieNode.info.singleIdentity()
@ -196,7 +195,7 @@ class FlowFrameworkTests {
assertEquals(1, bobNode.checkpointStorage.checkpoints().size) // confirm checkpoint assertEquals(1, bobNode.checkpointStorage.checkpoints().size) // confirm checkpoint
bobNode.services.networkMapCache.clearNetworkMapCache() bobNode.services.networkMapCache.clearNetworkMapCache()
} }
val node2b = mockNet.createNode(bobNode.internals.id) val node2b = mockNet.createNode(MockNodeParameters(bobNode.internals.id))
bobNode.internals.manuallyCloseDB() bobNode.internals.manuallyCloseDB()
val (firstAgain, fut1) = node2b.getSingleFlow<PingPongFlow>() val (firstAgain, fut1) = node2b.getSingleFlow<PingPongFlow>()
// Run the network which will also fire up the second flow. First message should get deduped. So message data stays in sync. // Run the network which will also fire up the second flow. First message should get deduped. So message data stays in sync.
@ -223,7 +222,7 @@ class FlowFrameworkTests {
@Test @Test
fun `sending to multiple parties`() { fun `sending to multiple parties`() {
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME) val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
mockNet.runNetwork() mockNet.runNetwork()
val charlie = charlieNode.info.singleIdentity() val charlie = charlieNode.info.singleIdentity()
bobNode.registerFlowFactory(SendFlow::class) { InitiatedReceiveFlow(it).nonTerminating() } bobNode.registerFlowFactory(SendFlow::class) { InitiatedReceiveFlow(it).nonTerminating() }
@ -256,7 +255,7 @@ class FlowFrameworkTests {
@Test @Test
fun `receiving from multiple parties`() { fun `receiving from multiple parties`() {
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME) val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
mockNet.runNetwork() mockNet.runNetwork()
val charlie = charlieNode.info.singleIdentity() val charlie = charlieNode.info.singleIdentity()
val bobPayload = "Test 1" val bobPayload = "Test 1"
@ -410,7 +409,7 @@ class FlowFrameworkTests {
@Test @Test
fun `FlowException propagated in invocation chain`() { fun `FlowException propagated in invocation chain`() {
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME) val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
mockNet.runNetwork() mockNet.runNetwork()
val charlie = charlieNode.info.singleIdentity() val charlie = charlieNode.info.singleIdentity()
@ -425,7 +424,7 @@ class FlowFrameworkTests {
@Test @Test
fun `FlowException thrown and there is a 3rd unrelated party flow`() { fun `FlowException thrown and there is a 3rd unrelated party flow`() {
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME) val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
mockNet.runNetwork() mockNet.runNetwork()
val charlie = charlieNode.info.singleIdentity() val charlie = charlieNode.info.singleIdentity()
@ -674,7 +673,7 @@ class FlowFrameworkTests {
private inline fun <reified P : FlowLogic<*>> StartedNode<MockNode>.restartAndGetRestoredFlow() = internals.run { private inline fun <reified P : FlowLogic<*>> StartedNode<MockNode>.restartAndGetRestoredFlow() = internals.run {
disableDBCloseOnStop() // Handover DB to new node copy disableDBCloseOnStop() // Handover DB to new node copy
stop() stop()
val newNode = mockNet.createNode(id) val newNode = mockNet.createNode(MockNodeParameters(id))
newNode.internals.acceptableLiveFiberCountOnStop = 1 newNode.internals.acceptableLiveFiberCountOnStop = 1
manuallyCloseDB() manuallyCloseDB()
mockNet.runNetwork() // allow NetworkMapService messages to stabilise and thus start the state machine mockNet.runNetwork() // allow NetworkMapService messages to stabilise and thus start the state machine

View File

@ -17,6 +17,7 @@ import net.corda.node.services.api.StartedNodeServices
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -37,7 +38,7 @@ class NotaryServiceTests {
fun setup() { fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts")) mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
val notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name, validating = false) val notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name, validating = false)
aliceServices = mockNet.createNode(legalName = ALICE_NAME).services aliceServices = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME)).services
mockNet.runNetwork() // Clear network map registration messages mockNet.runNetwork() // Clear network map registration messages
notaryServices = notaryNode.services notaryServices = notaryNode.services
notary = notaryServices.getDefaultNotary() notary = notaryServices.getDefaultNotary()

View File

@ -18,6 +18,7 @@ import net.corda.node.services.issueInvalidState
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -37,7 +38,7 @@ class ValidatingNotaryServiceTests {
fun setup() { fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts")) mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
val notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name) val notaryNode = mockNet.createNotaryNode(legalName = DUMMY_NOTARY.name)
val aliceNode = mockNet.createNode(legalName = ALICE_NAME) val aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
mockNet.runNetwork() // Clear network map registration messages mockNet.runNetwork() // Clear network map registration messages
notaryServices = notaryNode.services notaryServices = notaryNode.services
aliceServices = aliceNode.services aliceServices = aliceNode.services

View File

@ -25,15 +25,13 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.services.api.VaultServiceInternal import net.corda.node.services.api.VaultServiceInternal
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.chooseIdentity import net.corda.testing.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.rigorousMock import net.corda.testing.rigorousMock
import net.corda.testing.node.MockNodeArgs
import net.corda.testing.node.MockNodeParameters
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test
import java.math.BigInteger
import java.security.KeyPair
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
import kotlin.reflect.jvm.jvmName import kotlin.reflect.jvm.jvmName
@ -72,7 +70,7 @@ class NodePair(private val mockNet: MockNetwork) {
while (!serverRunning.get()) mockNet.runNetwork(1) while (!serverRunning.get()) mockNet.runNetwork(1)
if (rebootClient) { if (rebootClient) {
client.dispose() client.dispose()
client = mockNet.createNode(client.internals.id) client = mockNet.createNode(MockNodeParameters(client.internals.id))
} }
return uncheckedCast(client.smm.allStateMachines.single().stateMachine) return uncheckedCast(client.smm.allStateMachines.single().stateMachine)
} }
@ -83,8 +81,8 @@ class VaultSoftLockManagerTest {
doNothing().whenever(it).softLockRelease(any(), anyOrNull()) doNothing().whenever(it).softLockRelease(any(), anyOrNull())
} }
private val mockNet = MockNetwork(cordappPackages = listOf(ContractImpl::class.packageName), defaultFactory = object : MockNetwork.Factory<MockNetwork.MockNode> { private val mockNet = MockNetwork(cordappPackages = listOf(ContractImpl::class.packageName), defaultFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
override fun create(config: NodeConfiguration, network: MockNetwork, id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): MockNetwork.MockNode { override fun create(args: MockNodeArgs): MockNetwork.MockNode {
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) { return object : MockNetwork.MockNode(args) {
override fun makeVaultService(keyManagementService: KeyManagementService, stateLoader: StateLoader): VaultServiceInternal { override fun makeVaultService(keyManagementService: KeyManagementService, stateLoader: StateLoader): VaultServiceInternal {
val realVault = super.makeVaultService(keyManagementService, stateLoader) val realVault = super.makeVaultService(keyManagementService, stateLoader)
return object : VaultServiceInternal by realVault { return object : VaultServiceInternal by realVault {

View File

@ -1,5 +1,7 @@
package net.corda.netmap.simulation package net.corda.netmap.simulation
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.uncheckedCast import net.corda.core.internal.uncheckedCast
@ -8,20 +10,14 @@ import net.corda.finance.utils.CityDatabase
import net.corda.finance.utils.WorldMapLocation import net.corda.finance.utils.WorldMapLocation
import net.corda.irs.api.NodeInterestRates import net.corda.irs.api.NodeInterestRates
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_REGULATOR import net.corda.testing.DUMMY_REGULATOR
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.*
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.TestClock
import net.corda.testing.node.setTo
import net.corda.testing.testNodeConfiguration
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.math.BigInteger import java.math.BigInteger
import java.security.KeyPair
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneOffset import java.time.ZoneOffset
@ -39,6 +35,13 @@ import java.util.concurrent.Future
abstract class Simulation(val networkSendManuallyPumped: Boolean, abstract class Simulation(val networkSendManuallyPumped: Boolean,
runAsync: Boolean, runAsync: Boolean,
latencyInjector: InMemoryMessagingNetwork.LatencyCalculator?) { latencyInjector: InMemoryMessagingNetwork.LatencyCalculator?) {
companion object {
private val defaultParams // The get() is necessary so that entropyRoot isn't shared.
get() = MockNodeParameters(configOverrides = {
doReturn(makeTestDataSourceProperties(it.myLegalName.organisation)).whenever(it).dataSourceProperties
})
}
init { init {
if (!runAsync && latencyInjector != null) if (!runAsync && latencyInjector != null)
throw IllegalArgumentException("The latency injector is only useful when using manual pumping.") throw IllegalArgumentException("The latency injector is only useful when using manual pumping.")
@ -47,63 +50,23 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
val bankLocations = listOf(Pair("London", "GB"), Pair("Frankfurt", "DE"), Pair("Rome", "IT")) val bankLocations = listOf(Pair("London", "GB"), Pair("Frankfurt", "DE"), Pair("Rome", "IT"))
// This puts together a mock network of SimulatedNodes. // This puts together a mock network of SimulatedNodes.
open class SimulatedNode(args: MockNodeArgs) : MockNetwork.MockNode(args) {
open class SimulatedNode(config: NodeConfiguration, mockNet: MockNetwork,
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?,
entropyRoot: BigInteger)
: MockNetwork.MockNode(config, mockNet, id, notaryIdentity, entropyRoot) {
override val started: StartedNode<SimulatedNode>? get() = uncheckedCast(super.started) override val started: StartedNode<SimulatedNode>? get() = uncheckedCast(super.started)
override fun findMyLocation(): WorldMapLocation? { override fun findMyLocation(): WorldMapLocation? {
return configuration.myLegalName.locality.let { CityDatabase[it] } return configuration.myLegalName.locality.let { CityDatabase[it] }
} }
} }
inner class BankFactory : MockNetwork.Factory<SimulatedNode> { private object SimulatedNodeFactory : MockNetwork.Factory<SimulatedNode> {
var counter = 0 override fun create(args: MockNodeArgs) = SimulatedNode(args)
override fun create(config: NodeConfiguration, network: MockNetwork,
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): SimulatedNode {
val letter = 'A' + counter
val (city, country) = bankLocations[counter++ % bankLocations.size]
val cfg = testNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = CordaX500Name(organisation = "Bank $letter", locality = city, country = country))
return SimulatedNode(cfg, network, id, notaryIdentity, entropyRoot)
}
fun createAll(): List<SimulatedNode> {
return bankLocations.mapIndexed { i, _ ->
// Use deterministic seeds so the simulation is stable. Needed so that party owning keys are stable.
mockNet.createUnstartedNode(nodeFactory = this, entropyRoot = BigInteger.valueOf(i.toLong()))
}
}
}
val bankFactory = BankFactory()
object NotaryNodeFactory : MockNetwork.Factory<SimulatedNode> {
override fun create(config: NodeConfiguration, network: MockNetwork,
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): SimulatedNode {
requireNotNull(config.notary)
val cfg = testNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = DUMMY_NOTARY.name,
notaryConfig = config.notary)
return SimulatedNode(cfg, network, id, notaryIdentity, entropyRoot)
}
} }
object RatesOracleFactory : MockNetwork.Factory<SimulatedNode> { object RatesOracleFactory : MockNetwork.Factory<SimulatedNode> {
// TODO: Make a more realistic legal name // TODO: Make a more realistic legal name
val RATES_SERVICE_NAME = CordaX500Name(organisation = "Rates Service Provider", locality = "Madrid", country = "ES") val RATES_SERVICE_NAME = CordaX500Name(organisation = "Rates Service Provider", locality = "Madrid", country = "ES")
override fun create(config: NodeConfiguration, network: MockNetwork, override fun create(args: MockNodeArgs): SimulatedNode {
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): SimulatedNode { return object : SimulatedNode(args) {
val cfg = testNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = RATES_SERVICE_NAME)
return object : SimulatedNode(cfg, network, id, notaryIdentity, entropyRoot) {
override fun start() = super.start().apply { override fun start() = super.start().apply {
registerInitiatedFlow(NodeInterestRates.FixQueryHandler::class.java) registerInitiatedFlow(NodeInterestRates.FixQueryHandler::class.java)
registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java) registerInitiatedFlow(NodeInterestRates.FixSignHandler::class.java)
@ -117,33 +80,23 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
} }
} }
object RegulatorFactory : MockNetwork.Factory<SimulatedNode> {
override fun create(config: NodeConfiguration, network: MockNetwork,
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): SimulatedNode {
val cfg = testNodeConfiguration(
baseDirectory = config.baseDirectory,
myLegalName = DUMMY_REGULATOR.name)
return object : SimulatedNode(cfg, network, id, notaryIdentity, entropyRoot) {
// TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
// So we just fire a message at a node that doesn't know how to handle it, and it'll ignore it.
// But that's fine for visualisation purposes.
}
}
}
val mockNet = MockNetwork( val mockNet = MockNetwork(
networkSendManuallyPumped = networkSendManuallyPumped, networkSendManuallyPumped = networkSendManuallyPumped,
threadPerNode = runAsync, threadPerNode = runAsync,
cordappPackages = listOf("net.corda.irs.contract", "net.corda.finance.contract", "net.corda.irs")) cordappPackages = listOf("net.corda.irs.contract", "net.corda.finance.contract", "net.corda.irs"))
// This one must come first. val notary = mockNet.createNotaryNode(defaultParams.copy(legalName = DUMMY_NOTARY.name), false, SimulatedNodeFactory)
val notary = mockNet.createNotaryNode(validating = false, nodeFactory = NotaryNodeFactory) // TODO: Regulatory nodes don't actually exist properly, this is a last minute demo request.
val regulators = listOf(mockNet.createUnstartedNode(nodeFactory = RegulatorFactory)) // So we just fire a message at a node that doesn't know how to handle it, and it'll ignore it.
val ratesOracle = mockNet.createUnstartedNode(nodeFactory = RatesOracleFactory) // But that's fine for visualisation purposes.
val regulators = listOf(mockNet.createUnstartedNode(defaultParams.copy(legalName = DUMMY_REGULATOR.name), SimulatedNodeFactory))
val ratesOracle = mockNet.createUnstartedNode(defaultParams.copy(legalName = RatesOracleFactory.RATES_SERVICE_NAME), RatesOracleFactory)
// All nodes must be in one of these two lists for the purposes of the visualiser tool. // All nodes must be in one of these two lists for the purposes of the visualiser tool.
val serviceProviders: List<SimulatedNode> = listOf(notary.internals, ratesOracle) val serviceProviders: List<SimulatedNode> = listOf(notary.internals, ratesOracle)
val banks: List<SimulatedNode> = bankFactory.createAll() val banks: List<SimulatedNode> = bankLocations.mapIndexed { i, (city, country) ->
val legalName = CordaX500Name(organisation = "Bank ${'A' + i}", locality = city, country = country)
// Use deterministic seeds so the simulation is stable. Needed so that party owning keys are stable.
mockNet.createUnstartedNode(defaultParams.copy(legalName = legalName, entropyRoot = BigInteger.valueOf(i.toLong())), SimulatedNodeFactory)
}
val clocks = (serviceProviders + regulators + banks).map { it.platformClock as TestClock } val clocks = (serviceProviders + regulators + banks).map { it.platformClock as TestClock }
// These are used from the network visualiser tool. // These are used from the network visualiser tool.

View File

@ -10,7 +10,6 @@ import net.corda.core.node.ServiceHub
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.node.services.config.CertChainPolicyConfig import net.corda.node.services.config.CertChainPolicyConfig
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.config.VerifierType import net.corda.node.services.config.VerifierType
import net.corda.nodeapi.User import net.corda.nodeapi.User
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
@ -57,8 +56,7 @@ fun transaction(
fun testNodeConfiguration( fun testNodeConfiguration(
baseDirectory: Path, baseDirectory: Path,
myLegalName: CordaX500Name, myLegalName: CordaX500Name): NodeConfiguration {
notaryConfig: NotaryConfig? = null): NodeConfiguration {
abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters. abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters.
return rigorousMock<MockableNodeConfiguration>().also { return rigorousMock<MockableNodeConfiguration>().also {
doReturn(true).whenever(it).noNetworkMapServiceMode doReturn(true).whenever(it).noNetworkMapServiceMode
@ -68,7 +66,7 @@ fun testNodeConfiguration(
doReturn("cordacadevpass").whenever(it).keyStorePassword doReturn("cordacadevpass").whenever(it).keyStorePassword
doReturn("trustpass").whenever(it).trustStorePassword doReturn("trustpass").whenever(it).trustStorePassword
doReturn(emptyList<User>()).whenever(it).rpcUsers doReturn(emptyList<User>()).whenever(it).rpcUsers
doReturn(notaryConfig).whenever(it).notary doReturn(null).whenever(it).notary
doReturn(makeTestDataSourceProperties(myLegalName.organisation)).whenever(it).dataSourceProperties doReturn(makeTestDataSourceProperties(myLegalName.organisation)).whenever(it).dataSourceProperties
doReturn(makeTestDatabaseProperties()).whenever(it).database doReturn(makeTestDatabaseProperties()).whenever(it).database
doReturn("").whenever(it).emailAddress doReturn("").whenever(it).emailAddress

View File

@ -77,6 +77,34 @@ data class MockNetworkParameters(
fun setCordappPackages(cordappPackages: List<String>) = copy(cordappPackages = cordappPackages) fun setCordappPackages(cordappPackages: List<String>) = copy(cordappPackages = cordappPackages)
} }
/**
* @param notaryIdentity a set of service entries to use in place of the node's default service entries,
* for example where a node's service is part of a cluster.
* @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 behaviour of the [NodeConfiguration] mock object.
*/
@Suppress("unused")
data class MockNodeParameters(
val forcedID: Int? = null,
val legalName: CordaX500Name? = null,
val notaryIdentity: Pair<ServiceInfo, KeyPair>? = null,
val entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
val configOverrides: (NodeConfiguration) -> Any? = {}) {
fun setForcedID(forcedID: Int?) = copy(forcedID = forcedID)
fun setLegalName(legalName: CordaX500Name?) = copy(legalName = legalName)
fun setNotaryIdentity(notaryIdentity: Pair<ServiceInfo, KeyPair>?) = copy(notaryIdentity = notaryIdentity)
fun setEntropyRoot(entropyRoot: BigInteger) = copy(entropyRoot = entropyRoot)
fun setConfigOverrides(configOverrides: (NodeConfiguration) -> Any?) = copy(configOverrides = configOverrides)
}
data class MockNodeArgs(
val config: NodeConfiguration,
val network: MockNetwork,
val id: Int,
val notaryIdentity: Pair<ServiceInfo, KeyPair>?,
val entropyRoot: BigInteger)
/** /**
* A mock node brings up a suite of in-memory services in a fast manner suitable for unit testing. * A mock node brings up a suite of in-memory services in a fast manner suitable for unit testing.
* Components that do IO are either swapped out for mocks, or pointed to a [Jimfs] in memory filesystem or an in * Components that do IO are either swapped out for mocks, or pointed to a [Jimfs] in memory filesystem or an in
@ -118,24 +146,11 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
/** Allows customisation of how nodes are created. */ /** Allows customisation of how nodes are created. */
interface Factory<out N : MockNode> { interface Factory<out N : MockNode> {
/** fun create(args: MockNodeArgs): N
* @param config the configuration of the node to be created
* @param network a reference to the [MockNetwork] owning the node.
* @param id a unique identifier for the node.
* @param notaryIdentity is an additional override to use in place of the node's default notary service,
* main usage is for when the node is part of a notary cluster.
* @param entropyRoot the initial entropy value to use when generating keys. Defaults to an (insecure) random value,
* but can be overriden to cause nodes to have stable or colliding identity/service keys.
*/
fun create(config: NodeConfiguration, network: MockNetwork, id: Int,
notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): N
} }
object DefaultFactory : Factory<MockNode> { object DefaultFactory : Factory<MockNode> {
override fun create(config: NodeConfiguration, network: MockNetwork, override fun create(args: MockNodeArgs) = MockNode(args)
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): MockNode {
return MockNode(config, network, id, notaryIdentity, entropyRoot)
}
} }
/** /**
@ -161,19 +176,17 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
} }
} }
/** open class MockNode(args: MockNodeArgs) : AbstractNode(
* @param notaryIdentity is an additional override to use in place of the node's default notary service, args.config,
* main usage is for when the node is part of a notary cluster. TestClock(),
* @param entropyRoot the initial entropy value to use when generating keys. Defaults to an (insecure) random value, MOCK_VERSION_INFO,
* but can be overriden to cause nodes to have stable or colliding identity/service keys. CordappLoader.createDefaultWithTestPackages(args.config, args.network.cordappPackages),
*/ args.network.busyLatch) {
open class MockNode(config: NodeConfiguration, val mockNet = args.network
val mockNet: MockNetwork,
val id: Int,
internal val notaryIdentity: Pair<ServiceInfo, KeyPair>?,
val entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue())) :
AbstractNode(config, TestClock(), MOCK_VERSION_INFO, CordappLoader.createDefaultWithTestPackages(config, mockNet.cordappPackages), mockNet.busyLatch) {
override val networkMapAddress = null override val networkMapAddress = null
val id = args.id
internal val notaryIdentity = args.notaryIdentity
val entropyRoot = args.entropyRoot
var counter = entropyRoot var counter = entropyRoot
override val log: Logger = loggerFor<MockNode>() override val log: Logger = loggerFor<MockNode>()
override val serverThread: AffinityExecutor = override val serverThread: AffinityExecutor =
@ -279,56 +292,28 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
} }
} }
fun createUnstartedNode(forcedID: Int? = null, fun createUnstartedNode(parameters: MockNodeParameters = MockNodeParameters()) = createUnstartedNode(parameters, defaultFactory)
legalName: CordaX500Name? = null, notaryIdentity: Pair<ServiceInfo, KeyPair>? = null, fun <N : MockNode> createUnstartedNode(parameters: MockNodeParameters = MockNodeParameters(), nodeFactory: Factory<N>): N {
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), return createNodeImpl(parameters, nodeFactory, false)
configOverrides: (NodeConfiguration) -> Any? = {}): MockNode {
return createUnstartedNode(forcedID, defaultFactory, legalName, notaryIdentity, entropyRoot, configOverrides = configOverrides)
}
fun <N : MockNode> createUnstartedNode(forcedID: Int? = null, nodeFactory: Factory<N>,
legalName: CordaX500Name? = null, notaryIdentity: Pair<ServiceInfo, KeyPair>? = null,
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
configOverrides: (NodeConfiguration) -> Any? = {}): N {
return createNodeImpl(forcedID, nodeFactory, false, legalName, notaryIdentity, entropyRoot, configOverrides)
}
/**
* Returns a node, optionally created by the passed factory method.
* @param notaryIdentity a set of service entries to use in place of the node's default service entries,
* for example where a node's service is part of a cluster.
* @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 behaviour of the [NodeConfiguration] mock object.
*/
fun createNode(forcedID: Int? = null,
legalName: CordaX500Name? = null, notaryIdentity: Pair<ServiceInfo, KeyPair>? = null,
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
configOverrides: (NodeConfiguration) -> Any? = {}): StartedNode<MockNode> {
return createNode(forcedID, defaultFactory, legalName, notaryIdentity, entropyRoot, configOverrides = configOverrides)
} }
fun createNode(parameters: MockNodeParameters = MockNodeParameters()): StartedNode<MockNode> = createNode(parameters, defaultFactory)
/** Like the other [createNode] but takes a [Factory] and propagates its [MockNode] subtype. */ /** Like the other [createNode] but takes a [Factory] and propagates its [MockNode] subtype. */
fun <N : MockNode> createNode(forcedID: Int? = null, nodeFactory: Factory<N>, fun <N : MockNode> createNode(parameters: MockNodeParameters = MockNodeParameters(), nodeFactory: Factory<N>): StartedNode<N> {
legalName: CordaX500Name? = null, notaryIdentity: Pair<ServiceInfo, KeyPair>? = null, val node: StartedNode<N> = uncheckedCast(createNodeImpl(parameters, nodeFactory, true).started)!!
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()), ensureAllNetworkMapCachesHaveAllNodeInfos()
configOverrides: (NodeConfiguration) -> Any? = {}): StartedNode<N> { return node
return uncheckedCast(createNodeImpl(forcedID, nodeFactory, true, legalName, notaryIdentity, entropyRoot, configOverrides).started!!
.also { ensureAllNetworkMapCachesHaveAllNodeInfos() })
} }
private fun <N : MockNode> createNodeImpl(forcedID: Int?, nodeFactory: Factory<N>, private fun <N : MockNode> createNodeImpl(parameters: MockNodeParameters, nodeFactory: Factory<N>, start: Boolean): N {
start: Boolean, legalName: CordaX500Name?, notaryIdentity: Pair<ServiceInfo, KeyPair>?, val id = parameters.forcedID ?: nextNodeId++
entropyRoot: BigInteger,
configOverrides: (NodeConfiguration) -> Any?): N {
val id = forcedID ?: nextNodeId++
val config = testNodeConfiguration( val config = testNodeConfiguration(
baseDirectory = baseDirectory(id).createDirectories(), baseDirectory = baseDirectory(id).createDirectories(),
myLegalName = legalName ?: CordaX500Name(organisation = "Mock Company $id", locality = "London", country = "GB")).also { myLegalName = parameters.legalName ?: CordaX500Name(organisation = "Mock Company $id", locality = "London", country = "GB")).also {
doReturn(makeTestDataSourceProperties("node_${id}_net_$networkId")).whenever(it).dataSourceProperties doReturn(makeTestDataSourceProperties("node_${id}_net_$networkId")).whenever(it).dataSourceProperties
configOverrides(it) parameters.configOverrides(it)
} }
return nodeFactory.create(config, this, id, notaryIdentity, entropyRoot).apply { return nodeFactory.create(MockNodeArgs(config, this, id, parameters.notaryIdentity, parameters.entropyRoot)).apply {
if (start) { if (start) {
start() start()
if (threadPerNode) nodeReadyFuture.getOrThrow() // XXX: What about manually-started nodes? if (threadPerNode) nodeReadyFuture.getOrThrow() // XXX: What about manually-started nodes?
@ -364,23 +349,24 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
@JvmOverloads @JvmOverloads
fun createNotaryNode(legalName: CordaX500Name = DUMMY_NOTARY.name, validating: Boolean = true): StartedNode<MockNode> { fun createNotaryNode(legalName: CordaX500Name = DUMMY_NOTARY.name, validating: Boolean = true): StartedNode<MockNode> {
return createNode(legalName = legalName, configOverrides = { return createNode(MockNodeParameters(legalName = legalName, configOverrides = {
doReturn(NotaryConfig(validating)).whenever(it).notary doReturn(NotaryConfig(validating)).whenever(it).notary
}) }))
} }
fun <N : MockNode> createNotaryNode(legalName: CordaX500Name = DUMMY_NOTARY.name, fun <N : MockNode> createNotaryNode(parameters: MockNodeParameters = MockNodeParameters(legalName = DUMMY_NOTARY.name),
validating: Boolean = true, validating: Boolean = true,
nodeFactory: Factory<N>): StartedNode<N> { nodeFactory: Factory<N>): StartedNode<N> {
return createNode(legalName = legalName, nodeFactory = nodeFactory, configOverrides = { return createNode(parameters.copy(configOverrides = {
doReturn(NotaryConfig(validating)).whenever(it).notary doReturn(NotaryConfig(validating)).whenever(it).notary
}) parameters.configOverrides(it)
}), nodeFactory)
} }
@JvmOverloads @JvmOverloads
fun createPartyNode(legalName: CordaX500Name? = null, fun createPartyNode(legalName: CordaX500Name? = null,
notaryIdentity: Pair<ServiceInfo, KeyPair>? = null): StartedNode<MockNode> { notaryIdentity: Pair<ServiceInfo, KeyPair>? = null): StartedNode<MockNode> {
return createNode(legalName = legalName, notaryIdentity = notaryIdentity) return createNode(MockNodeParameters(legalName = legalName, notaryIdentity = notaryIdentity))
} }
@Suppress("unused") // This is used from the network visualiser tool. @Suppress("unused") // This is used from the network visualiser tool.