mirror of
https://github.com/corda/corda.git
synced 2025-06-17 06:38:21 +00:00
Introduce MockNodeParameters/Args (#1923)
This commit is contained in:
@ -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)
|
||||||
|
|
||||||
|
@ -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 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user