mirror of
https://github.com/corda/corda.git
synced 2025-04-06 19:07:08 +00:00
Introduce MockNodeParameters/Args (#1923)
This commit is contained in:
parent
7f6608deb5
commit
927924498b
@ -9,21 +9,19 @@ import net.corda.core.internal.FetchAttachmentsFlow
|
||||
import net.corda.core.internal.FetchDataFlow
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.persistence.NodeAttachmentService
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.testing.ALICE
|
||||
import net.corda.testing.ALICE_NAME
|
||||
import net.corda.testing.BOB
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeArgs
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import net.corda.testing.singleIdentity
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyPair
|
||||
import java.util.jar.JarOutputStream
|
||||
import java.util.zip.ZipEntry
|
||||
import kotlin.test.assertEquals
|
||||
@ -113,17 +111,14 @@ class AttachmentTests {
|
||||
@Test
|
||||
fun `malicious response`() {
|
||||
// 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> {
|
||||
override fun create(config: NodeConfiguration, network: MockNetwork,
|
||||
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?,
|
||||
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) {
|
||||
val aliceNode = mockNet.createNotaryNode(MockNodeParameters(legalName = ALICE.name), nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
|
||||
override fun create(args: MockNodeArgs): MockNetwork.MockNode {
|
||||
return object : MockNetwork.MockNode(args) {
|
||||
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false }
|
||||
}
|
||||
}
|
||||
}, validating = false)
|
||||
val bobNode = mockNet.createNode(legalName = BOB.name)
|
||||
|
||||
val bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB.name))
|
||||
mockNet.runNetwork()
|
||||
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.node.internal.InitiatedFlowFactory
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.persistence.NodeAttachmentService
|
||||
import net.corda.node.utilities.currentDBSession
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.testing.chooseIdentity
|
||||
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.Before
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.math.BigInteger
|
||||
import java.nio.charset.StandardCharsets.UTF_8
|
||||
import java.security.KeyPair
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlin.test.assertEquals
|
||||
@ -158,10 +156,9 @@ class AttachmentSerializationTest {
|
||||
|
||||
private fun rebootClientAndGetAttachmentContent(checkAttachmentsOnLoad: Boolean = true): String {
|
||||
client.dispose()
|
||||
client = mockNet.createNode(client.internals.id, object : MockNetwork.Factory<MockNetwork.MockNode> {
|
||||
override fun create(config: NodeConfiguration, network: MockNetwork,
|
||||
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) {
|
||||
client = mockNet.createNode(MockNodeParameters(client.internals.id), object : MockNetwork.Factory<MockNetwork.MockNode> {
|
||||
override fun create(args: MockNodeArgs): MockNetwork.MockNode {
|
||||
return object : MockNetwork.MockNode(args) {
|
||||
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.testing.chooseIdentity
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
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))
|
||||
try {
|
||||
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).
|
||||
existingConfig.dataSourceProperties.setProperty("maximumPoolSize", "2")
|
||||
existingConfig
|
||||
})
|
||||
|
||||
}))
|
||||
mockNet.startNodes()
|
||||
|
||||
// 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.getDefaultNotary
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import org.junit.After
|
||||
import org.junit.Test
|
||||
import java.nio.file.Paths
|
||||
@ -57,10 +58,10 @@ class BFTNotaryServiceTests {
|
||||
clusterName)
|
||||
val clusterAddresses = replicaIds.map { NetworkHostAndPort("localhost", 11000 + it * 10) }
|
||||
replicaIds.forEach { replicaId ->
|
||||
mockNet.createNode(configOverrides = {
|
||||
mockNet.createNode(MockNodeParameters(configOverrides = {
|
||||
val notary = NotaryConfig(validating = false, bftSMaRt = BFTSMaRtConfiguration(replicaId, clusterAddresses, exposeRaces = exposeRaces))
|
||||
doReturn(notary).whenever(it).notary
|
||||
})
|
||||
}))
|
||||
}
|
||||
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.node.internal.StartedNode
|
||||
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.checkpoints
|
||||
import net.corda.node.utilities.CordaPersistence
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.contracts.fillWithSomeTestCash
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockServices
|
||||
import net.corda.testing.node.pumpReceive
|
||||
import net.corda.testing.node.*
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -54,8 +49,6 @@ import org.junit.runners.Parameterized
|
||||
import rx.Observable
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
import java.util.jar.JarOutputStream
|
||||
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
|
||||
// that Bob was waiting on before the reboot occurred.
|
||||
bobNode = mockNet.createNode(bobAddr.id, object : MockNetwork.Factory<MockNetwork.MockNode> {
|
||||
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)
|
||||
|
||||
bobNode = mockNet.createNode(MockNodeParameters(bobAddr.id, BOB_NAME))
|
||||
// Find the future representing the result of this state machine again.
|
||||
val bobFuture = bobNode.smm.findStateMachines(BuyerAcceptor::class.java).single().second
|
||||
|
||||
@ -307,19 +294,16 @@ class TwoPartyTradeFlowTests(val anonymous: Boolean) {
|
||||
// of gets and puts.
|
||||
private fun makeNodeWithTracking(name: CordaX500Name): StartedNode<MockNetwork.MockNode> {
|
||||
// Create a node in the mock network ...
|
||||
return mockNet.createNode(nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
|
||||
override fun create(config: NodeConfiguration,
|
||||
network: MockNetwork,
|
||||
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?,
|
||||
entropyRoot: BigInteger): MockNetwork.MockNode {
|
||||
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) {
|
||||
return mockNet.createNode(MockNodeParameters(legalName = name), nodeFactory = object : MockNetwork.Factory<MockNetwork.MockNode> {
|
||||
override fun create(args: MockNodeArgs): MockNetwork.MockNode {
|
||||
return object : MockNetwork.MockNode(args) {
|
||||
// That constructs a recording tx storage
|
||||
override fun makeTransactionStorage(): WritableTransactionStorage {
|
||||
return RecordingTransactionStorage(database, super.makeTransactionStorage())
|
||||
}
|
||||
}
|
||||
}
|
||||
}, legalName = name)
|
||||
})
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -5,6 +5,7 @@ import net.corda.testing.ALICE
|
||||
import net.corda.testing.BOB
|
||||
import net.corda.testing.chooseIdentity
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Test
|
||||
@ -22,12 +23,12 @@ class NetworkMapCacheTest {
|
||||
@Test
|
||||
fun `key collision`() {
|
||||
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()
|
||||
|
||||
// Node A currently knows only about itself, so this returns node A
|
||||
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())
|
||||
|
||||
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.MockNetwork
|
||||
import net.corda.testing.node.MockNetwork.MockNode
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import net.corda.testing.node.pumpReceive
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatThrownBy
|
||||
@ -72,9 +73,8 @@ class FlowFrameworkTests {
|
||||
@Before
|
||||
fun start() {
|
||||
mockNet = MockNetwork(servicePeerAllocationStrategy = RoundRobin(), cordappPackages = listOf("net.corda.finance.contracts", "net.corda.testing.contracts"))
|
||||
aliceNode = mockNet.createNode(legalName = ALICE_NAME)
|
||||
bobNode = mockNet.createNode(legalName = BOB_NAME)
|
||||
|
||||
aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
|
||||
bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
|
||||
mockNet.runNetwork()
|
||||
|
||||
// We intentionally create our own notary and ignore the one provided by the network
|
||||
@ -176,8 +176,7 @@ class FlowFrameworkTests {
|
||||
|
||||
var sentCount = 0
|
||||
mockNet.messagingNetwork.sentMessages.toSessionTransfers().filter { it.isPayloadTransfer }.forEach { sentCount++ }
|
||||
|
||||
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME)
|
||||
val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
|
||||
val secondFlow = charlieNode.registerFlowFactory(PingPongFlow::class) { PingPongFlow(it, payload2) }
|
||||
mockNet.runNetwork()
|
||||
val charlie = charlieNode.info.singleIdentity()
|
||||
@ -196,7 +195,7 @@ class FlowFrameworkTests {
|
||||
assertEquals(1, bobNode.checkpointStorage.checkpoints().size) // confirm checkpoint
|
||||
bobNode.services.networkMapCache.clearNetworkMapCache()
|
||||
}
|
||||
val node2b = mockNet.createNode(bobNode.internals.id)
|
||||
val node2b = mockNet.createNode(MockNodeParameters(bobNode.internals.id))
|
||||
bobNode.internals.manuallyCloseDB()
|
||||
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.
|
||||
@ -223,7 +222,7 @@ class FlowFrameworkTests {
|
||||
|
||||
@Test
|
||||
fun `sending to multiple parties`() {
|
||||
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME)
|
||||
val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
|
||||
mockNet.runNetwork()
|
||||
val charlie = charlieNode.info.singleIdentity()
|
||||
bobNode.registerFlowFactory(SendFlow::class) { InitiatedReceiveFlow(it).nonTerminating() }
|
||||
@ -256,7 +255,7 @@ class FlowFrameworkTests {
|
||||
|
||||
@Test
|
||||
fun `receiving from multiple parties`() {
|
||||
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME)
|
||||
val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
|
||||
mockNet.runNetwork()
|
||||
val charlie = charlieNode.info.singleIdentity()
|
||||
val bobPayload = "Test 1"
|
||||
@ -410,7 +409,7 @@ class FlowFrameworkTests {
|
||||
|
||||
@Test
|
||||
fun `FlowException propagated in invocation chain`() {
|
||||
val charlieNode = mockNet.createNode(legalName = CHARLIE_NAME)
|
||||
val charlieNode = mockNet.createNode(MockNodeParameters(legalName = CHARLIE_NAME))
|
||||
mockNet.runNetwork()
|
||||
val charlie = charlieNode.info.singleIdentity()
|
||||
|
||||
@ -425,7 +424,7 @@ class FlowFrameworkTests {
|
||||
|
||||
@Test
|
||||
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()
|
||||
val charlie = charlieNode.info.singleIdentity()
|
||||
|
||||
@ -674,7 +673,7 @@ class FlowFrameworkTests {
|
||||
private inline fun <reified P : FlowLogic<*>> StartedNode<MockNode>.restartAndGetRestoredFlow() = internals.run {
|
||||
disableDBCloseOnStop() // Handover DB to new node copy
|
||||
stop()
|
||||
val newNode = mockNet.createNode(id)
|
||||
val newNode = mockNet.createNode(MockNodeParameters(id))
|
||||
newNode.internals.acceptableLiveFiberCountOnStop = 1
|
||||
manuallyCloseDB()
|
||||
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.contracts.DummyContract
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -37,7 +38,7 @@ class NotaryServiceTests {
|
||||
fun setup() {
|
||||
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
|
||||
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
|
||||
notaryServices = notaryNode.services
|
||||
notary = notaryServices.getDefaultNotary()
|
||||
|
@ -18,6 +18,7 @@ import net.corda.node.services.issueInvalidState
|
||||
import net.corda.testing.*
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
@ -37,7 +38,7 @@ class ValidatingNotaryServiceTests {
|
||||
fun setup() {
|
||||
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts"))
|
||||
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
|
||||
notaryServices = notaryNode.services
|
||||
aliceServices = aliceNode.services
|
||||
|
@ -25,15 +25,13 @@ import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.unwrap
|
||||
import net.corda.node.internal.InitiatedFlowFactory
|
||||
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.node.MockNetwork
|
||||
import net.corda.testing.rigorousMock
|
||||
import net.corda.testing.node.MockNodeArgs
|
||||
import net.corda.testing.node.MockNodeParameters
|
||||
import org.junit.After
|
||||
import org.junit.Test
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyPair
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.reflect.jvm.jvmName
|
||||
@ -72,7 +70,7 @@ class NodePair(private val mockNet: MockNetwork) {
|
||||
while (!serverRunning.get()) mockNet.runNetwork(1)
|
||||
if (rebootClient) {
|
||||
client.dispose()
|
||||
client = mockNet.createNode(client.internals.id)
|
||||
client = mockNet.createNode(MockNodeParameters(client.internals.id))
|
||||
}
|
||||
return uncheckedCast(client.smm.allStateMachines.single().stateMachine)
|
||||
}
|
||||
@ -83,8 +81,8 @@ class VaultSoftLockManagerTest {
|
||||
doNothing().whenever(it).softLockRelease(any(), anyOrNull())
|
||||
}
|
||||
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 {
|
||||
return object : MockNetwork.MockNode(config, network, id, notaryIdentity, entropyRoot) {
|
||||
override fun create(args: MockNodeArgs): MockNetwork.MockNode {
|
||||
return object : MockNetwork.MockNode(args) {
|
||||
override fun makeVaultService(keyManagementService: KeyManagementService, stateLoader: StateLoader): VaultServiceInternal {
|
||||
val realVault = super.makeVaultService(keyManagementService, stateLoader)
|
||||
return object : VaultServiceInternal by realVault {
|
||||
|
@ -1,5 +1,7 @@
|
||||
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.identity.CordaX500Name
|
||||
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.irs.api.NodeInterestRates
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.statemachine.StateMachineManager
|
||||
import net.corda.nodeapi.internal.ServiceInfo
|
||||
import net.corda.testing.DUMMY_NOTARY
|
||||
import net.corda.testing.DUMMY_REGULATOR
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.TestClock
|
||||
import net.corda.testing.node.setTo
|
||||
import net.corda.testing.testNodeConfiguration
|
||||
import net.corda.testing.node.*
|
||||
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
|
||||
import rx.Observable
|
||||
import rx.subjects.PublishSubject
|
||||
import java.math.BigInteger
|
||||
import java.security.KeyPair
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
@ -39,6 +35,13 @@ import java.util.concurrent.Future
|
||||
abstract class Simulation(val networkSendManuallyPumped: Boolean,
|
||||
runAsync: Boolean,
|
||||
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 {
|
||||
if (!runAsync && latencyInjector != null)
|
||||
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"))
|
||||
|
||||
// This puts together a mock network of SimulatedNodes.
|
||||
|
||||
open class SimulatedNode(config: NodeConfiguration, mockNet: MockNetwork,
|
||||
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?,
|
||||
entropyRoot: BigInteger)
|
||||
: MockNetwork.MockNode(config, mockNet, id, notaryIdentity, entropyRoot) {
|
||||
open class SimulatedNode(args: MockNodeArgs) : MockNetwork.MockNode(args) {
|
||||
override val started: StartedNode<SimulatedNode>? get() = uncheckedCast(super.started)
|
||||
override fun findMyLocation(): WorldMapLocation? {
|
||||
return configuration.myLegalName.locality.let { CityDatabase[it] }
|
||||
}
|
||||
}
|
||||
|
||||
inner class BankFactory : MockNetwork.Factory<SimulatedNode> {
|
||||
var counter = 0
|
||||
|
||||
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)
|
||||
}
|
||||
private object SimulatedNodeFactory : MockNetwork.Factory<SimulatedNode> {
|
||||
override fun create(args: MockNodeArgs) = SimulatedNode(args)
|
||||
}
|
||||
|
||||
object RatesOracleFactory : MockNetwork.Factory<SimulatedNode> {
|
||||
// TODO: Make a more realistic legal name
|
||||
val RATES_SERVICE_NAME = CordaX500Name(organisation = "Rates Service Provider", locality = "Madrid", country = "ES")
|
||||
|
||||
override fun create(config: NodeConfiguration, network: MockNetwork,
|
||||
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): SimulatedNode {
|
||||
val cfg = testNodeConfiguration(
|
||||
baseDirectory = config.baseDirectory,
|
||||
myLegalName = RATES_SERVICE_NAME)
|
||||
return object : SimulatedNode(cfg, network, id, notaryIdentity, entropyRoot) {
|
||||
override fun create(args: MockNodeArgs): SimulatedNode {
|
||||
return object : SimulatedNode(args) {
|
||||
override fun start() = super.start().apply {
|
||||
registerInitiatedFlow(NodeInterestRates.FixQueryHandler::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(
|
||||
networkSendManuallyPumped = networkSendManuallyPumped,
|
||||
threadPerNode = runAsync,
|
||||
cordappPackages = listOf("net.corda.irs.contract", "net.corda.finance.contract", "net.corda.irs"))
|
||||
// This one must come first.
|
||||
val notary = mockNet.createNotaryNode(validating = false, nodeFactory = NotaryNodeFactory)
|
||||
val regulators = listOf(mockNet.createUnstartedNode(nodeFactory = RegulatorFactory))
|
||||
val ratesOracle = mockNet.createUnstartedNode(nodeFactory = RatesOracleFactory)
|
||||
|
||||
val notary = mockNet.createNotaryNode(defaultParams.copy(legalName = DUMMY_NOTARY.name), false, SimulatedNodeFactory)
|
||||
// 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 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.
|
||||
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 }
|
||||
|
||||
// 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.node.services.config.CertChainPolicyConfig
|
||||
import net.corda.node.services.config.NodeConfiguration
|
||||
import net.corda.node.services.config.NotaryConfig
|
||||
import net.corda.node.services.config.VerifierType
|
||||
import net.corda.nodeapi.User
|
||||
import net.corda.testing.node.MockServices
|
||||
@ -57,8 +56,7 @@ fun transaction(
|
||||
|
||||
fun testNodeConfiguration(
|
||||
baseDirectory: Path,
|
||||
myLegalName: CordaX500Name,
|
||||
notaryConfig: NotaryConfig? = null): NodeConfiguration {
|
||||
myLegalName: CordaX500Name): NodeConfiguration {
|
||||
abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters.
|
||||
return rigorousMock<MockableNodeConfiguration>().also {
|
||||
doReturn(true).whenever(it).noNetworkMapServiceMode
|
||||
@ -68,7 +66,7 @@ fun testNodeConfiguration(
|
||||
doReturn("cordacadevpass").whenever(it).keyStorePassword
|
||||
doReturn("trustpass").whenever(it).trustStorePassword
|
||||
doReturn(emptyList<User>()).whenever(it).rpcUsers
|
||||
doReturn(notaryConfig).whenever(it).notary
|
||||
doReturn(null).whenever(it).notary
|
||||
doReturn(makeTestDataSourceProperties(myLegalName.organisation)).whenever(it).dataSourceProperties
|
||||
doReturn(makeTestDatabaseProperties()).whenever(it).database
|
||||
doReturn("").whenever(it).emailAddress
|
||||
|
@ -77,6 +77,34 @@ data class MockNetworkParameters(
|
||||
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.
|
||||
* 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. */
|
||||
interface Factory<out N : MockNode> {
|
||||
/**
|
||||
* @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
|
||||
fun create(args: MockNodeArgs): N
|
||||
}
|
||||
|
||||
object DefaultFactory : Factory<MockNode> {
|
||||
override fun create(config: NodeConfiguration, network: MockNetwork,
|
||||
id: Int, notaryIdentity: Pair<ServiceInfo, KeyPair>?, entropyRoot: BigInteger): MockNode {
|
||||
return MockNode(config, network, id, notaryIdentity, entropyRoot)
|
||||
}
|
||||
override fun create(args: MockNodeArgs) = MockNode(args)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,19 +176,17 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
open class MockNode(config: NodeConfiguration,
|
||||
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) {
|
||||
open class MockNode(args: MockNodeArgs) : AbstractNode(
|
||||
args.config,
|
||||
TestClock(),
|
||||
MOCK_VERSION_INFO,
|
||||
CordappLoader.createDefaultWithTestPackages(args.config, args.network.cordappPackages),
|
||||
args.network.busyLatch) {
|
||||
val mockNet = args.network
|
||||
override val networkMapAddress = null
|
||||
val id = args.id
|
||||
internal val notaryIdentity = args.notaryIdentity
|
||||
val entropyRoot = args.entropyRoot
|
||||
var counter = entropyRoot
|
||||
override val log: Logger = loggerFor<MockNode>()
|
||||
override val serverThread: AffinityExecutor =
|
||||
@ -279,56 +292,28 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
|
||||
}
|
||||
}
|
||||
|
||||
fun createUnstartedNode(forcedID: Int? = null,
|
||||
legalName: CordaX500Name? = null, notaryIdentity: Pair<ServiceInfo, KeyPair>? = null,
|
||||
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
|
||||
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 createUnstartedNode(parameters: MockNodeParameters = MockNodeParameters()) = createUnstartedNode(parameters, defaultFactory)
|
||||
fun <N : MockNode> createUnstartedNode(parameters: MockNodeParameters = MockNodeParameters(), nodeFactory: Factory<N>): N {
|
||||
return createNodeImpl(parameters, nodeFactory, false)
|
||||
}
|
||||
|
||||
fun createNode(parameters: MockNodeParameters = MockNodeParameters()): StartedNode<MockNode> = createNode(parameters, defaultFactory)
|
||||
/** Like the other [createNode] but takes a [Factory] and propagates its [MockNode] subtype. */
|
||||
fun <N : MockNode> createNode(forcedID: Int? = null, nodeFactory: Factory<N>,
|
||||
legalName: CordaX500Name? = null, notaryIdentity: Pair<ServiceInfo, KeyPair>? = null,
|
||||
entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
|
||||
configOverrides: (NodeConfiguration) -> Any? = {}): StartedNode<N> {
|
||||
return uncheckedCast(createNodeImpl(forcedID, nodeFactory, true, legalName, notaryIdentity, entropyRoot, configOverrides).started!!
|
||||
.also { ensureAllNetworkMapCachesHaveAllNodeInfos() })
|
||||
fun <N : MockNode> createNode(parameters: MockNodeParameters = MockNodeParameters(), nodeFactory: Factory<N>): StartedNode<N> {
|
||||
val node: StartedNode<N> = uncheckedCast(createNodeImpl(parameters, nodeFactory, true).started)!!
|
||||
ensureAllNetworkMapCachesHaveAllNodeInfos()
|
||||
return node
|
||||
}
|
||||
|
||||
private fun <N : MockNode> createNodeImpl(forcedID: Int?, nodeFactory: Factory<N>,
|
||||
start: Boolean, legalName: CordaX500Name?, notaryIdentity: Pair<ServiceInfo, KeyPair>?,
|
||||
entropyRoot: BigInteger,
|
||||
configOverrides: (NodeConfiguration) -> Any?): N {
|
||||
val id = forcedID ?: nextNodeId++
|
||||
private fun <N : MockNode> createNodeImpl(parameters: MockNodeParameters, nodeFactory: Factory<N>, start: Boolean): N {
|
||||
val id = parameters.forcedID ?: nextNodeId++
|
||||
val config = testNodeConfiguration(
|
||||
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
|
||||
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) {
|
||||
start()
|
||||
if (threadPerNode) nodeReadyFuture.getOrThrow() // XXX: What about manually-started nodes?
|
||||
@ -364,23 +349,24 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
|
||||
|
||||
@JvmOverloads
|
||||
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
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fun <N : MockNode> createNotaryNode(legalName: CordaX500Name = DUMMY_NOTARY.name,
|
||||
fun <N : MockNode> createNotaryNode(parameters: MockNodeParameters = MockNodeParameters(legalName = DUMMY_NOTARY.name),
|
||||
validating: Boolean = true,
|
||||
nodeFactory: Factory<N>): StartedNode<N> {
|
||||
return createNode(legalName = legalName, nodeFactory = nodeFactory, configOverrides = {
|
||||
return createNode(parameters.copy(configOverrides = {
|
||||
doReturn(NotaryConfig(validating)).whenever(it).notary
|
||||
})
|
||||
parameters.configOverrides(it)
|
||||
}), nodeFactory)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun createPartyNode(legalName: CordaX500Name? = null,
|
||||
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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user