CORDA-939 - Don't expose StartedNode and AbstractNode as part of public test api (#2472) (#2505)

* Don't expose StartedNode via Node Driver

* Dont expose StartedNode/Abstract Node via MockNetwork

* Remove internal var from constructor as it doesn't hide from public api and change to internal initialisation method

* Update api

* Rename MockNode to StartedMockNode to avoid confusion
Update documentation
Update api-current.txt

* Fix typo

* Fix test failure

* Modify flow tests to use internal mock network and remove additional internal exposures from StartedMockNode

* Fix api-current

* Change InProcess and OutOfProcess to interfaces

* Explicitly declare MockNetwork parameters
Dont expose StateMachineManager
Move affected tests to use internal mock network

* Fix api-current

* Changes requested via review

* Fix IRS Demo address

* Fix api

* Remove internal attribute from classes in internal package

* Remove accidentally added code

* Move useHttps into NodeHandleInternal

* Remove duplicated code

* Update api-current

* Make webAddress internal on NodeHandle

* Make sure parameters in public api are explicitly specified

* Use correct address in IRS Demo

* Get webaddress from webserver handle

* Update api-current

# Conflicts:
#	.ci/api-current.txt
This commit is contained in:
Anthony Keenan 2018-02-12 13:26:56 +00:00 committed by Katelyn Baker
parent 805178debc
commit e363090f30
62 changed files with 622 additions and 405 deletions

View File

@ -75,7 +75,7 @@ class NodeMonitorModelTest {
vaultUpdates = monitor.vaultUpdates.bufferUntilSubscribed() vaultUpdates = monitor.vaultUpdates.bufferUntilSubscribed()
networkMapUpdates = monitor.networkMap.bufferUntilSubscribed() networkMapUpdates = monitor.networkMap.bufferUntilSubscribed()
monitor.register(aliceNodeHandle.configuration.rpcOptions.address!!, cashUser.username, cashUser.password) monitor.register(aliceNodeHandle.rpcAddress, cashUser.username, cashUser.password)
rpc = monitor.proxyObservable.value!! rpc = monitor.proxyObservable.value!!
notaryParty = defaultNotaryIdentity notaryParty = defaultNotaryIdentity
@ -83,7 +83,7 @@ class NodeMonitorModelTest {
bobNode = bobNodeHandle.nodeInfo bobNode = bobNodeHandle.nodeInfo
val monitorBob = NodeMonitorModel() val monitorBob = NodeMonitorModel()
stateMachineUpdatesBob = monitorBob.stateMachineUpdates.bufferUntilSubscribed() stateMachineUpdatesBob = monitorBob.stateMachineUpdates.bufferUntilSubscribed()
monitorBob.register(bobNodeHandle.configuration.rpcOptions.address!!, cashUser.username, cashUser.password) monitorBob.register(bobNodeHandle.rpcAddress, cashUser.username, cashUser.password)
rpcBob = monitorBob.proxyObservable.value!! rpcBob = monitorBob.proxyObservable.value!!
runTest() runTest()
} }

View File

@ -3,9 +3,9 @@ package net.corda.core.flows;
import co.paralleluniverse.fibers.Suspendable; import co.paralleluniverse.fibers.Suspendable;
import com.google.common.primitives.Primitives; import com.google.common.primitives.Primitives;
import net.corda.core.identity.Party; import net.corda.core.identity.Party;
import net.corda.node.internal.StartedNode;
import net.corda.testing.core.TestConstants; import net.corda.testing.core.TestConstants;
import net.corda.testing.node.MockNetwork; import net.corda.testing.node.MockNetwork;
import net.corda.testing.node.StartedMockNode;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -21,8 +21,8 @@ import static net.corda.testing.node.NodeTestUtils.startFlow;
public class FlowsInJavaTest { public class FlowsInJavaTest {
private final MockNetwork mockNet = new MockNetwork(emptyList()); private final MockNetwork mockNet = new MockNetwork(emptyList());
private StartedNode<MockNetwork.MockNode> aliceNode; private StartedMockNode aliceNode;
private StartedNode<MockNetwork.MockNode> bobNode; private StartedMockNode bobNode;
private Party bob; private Party bob;
@Before @Before

View File

@ -15,6 +15,7 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -27,11 +28,11 @@ import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
class AttachmentTests { class AttachmentTests {
lateinit var mockNet: MockNetwork lateinit var mockNet: InternalMockNetwork
@Before @Before
fun setUp() { fun setUp() {
mockNet = MockNetwork(emptyList()) mockNet = InternalMockNetwork(emptyList())
} }
@After @After
@ -100,7 +101,7 @@ class AttachmentTests {
fun maliciousResponse() { fun maliciousResponse() {
// 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.createNode(MockNodeParameters(legalName = ALICE_NAME), nodeFactory = { args -> val aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME), nodeFactory = { args ->
object : MockNetwork.MockNode(args) { object : InternalMockNetwork.MockNode(args) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false } override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = false }
} }
}) })

View File

@ -11,11 +11,11 @@ import net.corda.core.identity.groupAbstractPartyByWellKnownParty
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
@ -30,9 +30,9 @@ class CollectSignaturesFlowTests {
} }
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var aliceNode: StartedNode<MockNetwork.MockNode> private lateinit var aliceNode: StartedMockNode
private lateinit var bobNode: StartedNode<MockNetwork.MockNode> private lateinit var bobNode: StartedMockNode
private lateinit var charlieNode: StartedNode<MockNetwork.MockNode> private lateinit var charlieNode: StartedMockNode
private lateinit var alice: Party private lateinit var alice: Party
private lateinit var bob: Party private lateinit var bob: Party
private lateinit var charlie: Party private lateinit var charlie: Party

View File

@ -19,17 +19,14 @@ import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.SecureCordaRPCOps import net.corda.node.internal.SecureCordaRPCOps
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.Permissions.Companion.startFlow import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME
import net.corda.testing.node.User
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyContractV2 import net.corda.testing.contracts.DummyContractV2
import net.corda.testing.node.internal.RPCDriverDSL import net.corda.testing.core.ALICE_NAME
import net.corda.testing.node.internal.rpcDriver import net.corda.testing.core.BOB_NAME
import net.corda.testing.node.internal.rpcTestUser
import net.corda.testing.node.internal.startRpcClient
import net.corda.testing.node.MockNetwork
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.User
import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -40,16 +37,16 @@ import kotlin.test.assertFailsWith
import kotlin.test.assertTrue import kotlin.test.assertTrue
class ContractUpgradeFlowTest { class ContractUpgradeFlowTest {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNetwork.MockNode> private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNetwork.MockNode> private lateinit var bobNode: StartedNode<MockNode>
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var alice: Party private lateinit var alice: Party
private lateinit var bob: Party private lateinit var bob: Party
@Before @Before
fun setup() { fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset", "net.corda.core.flows")) mockNet = InternalMockNetwork(cordappPackages = listOf("net.corda.testing.contracts", "net.corda.finance.contracts.asset", "net.corda.core.flows"))
aliceNode = mockNet.createPartyNode(ALICE_NAME) aliceNode = mockNet.createPartyNode(ALICE_NAME)
bobNode = mockNet.createPartyNode(BOB_NAME) bobNode = mockNet.createPartyNode(BOB_NAME)
notary = mockNet.defaultNotaryIdentity notary = mockNet.defaultNotaryIdentity
@ -103,7 +100,7 @@ class ContractUpgradeFlowTest {
val result = resultFuture.getOrThrow() val result = resultFuture.getOrThrow()
fun check(node: StartedNode<*>) { fun check(node: StartedNode<MockNode>) {
val nodeStx = node.database.transaction { val nodeStx = node.database.transaction {
node.services.validatedTransactions.getTransaction(result.ref.txhash) node.services.validatedTransactions.getTransaction(result.ref.txhash)
} }
@ -123,7 +120,7 @@ class ContractUpgradeFlowTest {
check(bobNode) check(bobNode)
} }
private fun RPCDriverDSL.startProxy(node: StartedNode<*>, user: User): CordaRPCOps { private fun RPCDriverDSL.startProxy(node: StartedNode<MockNode>, user: User): CordaRPCOps {
return startRpcClient<CordaRPCOps>( return startRpcClient<CordaRPCOps>(
rpcAddress = startRpcServer( rpcAddress = startRpcServer(
rpcUser = user, rpcUser = user,

View File

@ -5,6 +5,8 @@ import net.corda.core.utilities.UntrustworthyData
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.testing.node.StartedMockNode
import net.corda.testing.node.internal.InternalMockNetwork
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
@ -37,14 +39,14 @@ class NoAnswer(private val closure: () -> Unit = {}) : FlowLogic<Unit>() {
/** /**
* Allows to register a flow of type [R] against an initiating flow of type [I]. * Allows to register a flow of type [R] against an initiating flow of type [I].
*/ */
inline fun <I : FlowLogic<*>, reified R : FlowLogic<*>> StartedNode<*>.registerInitiatedFlow(initiatingFlowType: KClass<I>, crossinline construct: (session: FlowSession) -> R) { inline fun <I : FlowLogic<*>, reified R : FlowLogic<*>> StartedNode<InternalMockNetwork.MockNode>.registerInitiatedFlow(initiatingFlowType: KClass<I>, crossinline construct: (session: FlowSession) -> R) {
internalRegisterFlowFactory(initiatingFlowType.java, InitiatedFlowFactory.Core { session -> construct(session) }, R::class.javaObjectType, true) internalRegisterFlowFactory(initiatingFlowType.java, InitiatedFlowFactory.Core { session -> construct(session) }, R::class.javaObjectType, true)
} }
/** /**
* Allows to register a flow of type [Answer] against an initiating flow of type [I], returning a valure of type [R]. * Allows to register a flow of type [Answer] against an initiating flow of type [I], returning a valure of type [R].
*/ */
inline fun <I : FlowLogic<*>, reified R : Any> StartedNode<*>.registerAnswer(initiatingFlowType: KClass<I>, value: R) { inline fun <I : FlowLogic<*>, reified R : Any> StartedNode<InternalMockNetwork.MockNode>.registerAnswer(initiatingFlowType: KClass<I>, value: R) {
internalRegisterFlowFactory(initiatingFlowType.java, InitiatedFlowFactory.Core { session -> Answer(session, value) }, Answer::class.javaObjectType, true) internalRegisterFlowFactory(initiatingFlowType.java, InitiatedFlowFactory.Core { session -> Answer(session, value) }, Answer::class.javaObjectType, true)
} }

View File

@ -5,15 +5,15 @@ import net.corda.core.identity.Party
import net.corda.core.utilities.UntrustworthyData import net.corda.core.utilities.UntrustworthyData
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.testing.node.MockNetwork
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
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
class ReceiveMultipleFlowTests { class ReceiveMultipleFlowTests {
private val mockNet = MockNetwork(emptyList()) private val mockNet = InternalMockNetwork(emptyList())
private val nodes = (0..2).map { mockNet.createPartyNode() } private val nodes = (0..2).map { mockNet.createPartyNode() }
@After @After
fun stopNodes() { fun stopNodes() {

View File

@ -8,10 +8,10 @@ import net.corda.core.identity.Party
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.sequence import net.corda.core.utilities.sequence
import net.corda.node.internal.StartedNode
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.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -28,9 +28,9 @@ import kotlin.test.assertNull
// DOCSTART 3 // DOCSTART 3
class ResolveTransactionsFlowTest { class ResolveTransactionsFlowTest {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var notaryNode: StartedNode<MockNetwork.MockNode> private lateinit var notaryNode: StartedMockNode
private lateinit var megaCorpNode: StartedNode<MockNetwork.MockNode> private lateinit var megaCorpNode: StartedMockNode
private lateinit var miniCorpNode: StartedNode<MockNetwork.MockNode> private lateinit var miniCorpNode: StartedMockNode
private lateinit var megaCorp: Party private lateinit var megaCorp: Party
private lateinit var miniCorp: Party private lateinit var miniCorp: Party
private lateinit var notary: Party private lateinit var notary: Party

View File

@ -21,6 +21,7 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.MockNodeParameters
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -63,14 +64,14 @@ private fun updateAttachment(attachmentId: SecureHash, data: ByteArray) {
} }
class AttachmentSerializationTest { class AttachmentSerializationTest {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var server: StartedNode<MockNetwork.MockNode> private lateinit var server: StartedNode<InternalMockNetwork.MockNode>
private lateinit var client: StartedNode<MockNetwork.MockNode> private lateinit var client: StartedNode<InternalMockNetwork.MockNode>
private lateinit var serverIdentity: Party private lateinit var serverIdentity: Party
@Before @Before
fun setUp() { fun setUp() {
mockNet = MockNetwork(emptyList()) mockNet = InternalMockNetwork(emptyList())
server = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME)) server = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
client = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME)) client = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
client.internals.disableDBCloseOnStop() // Otherwise the in-memory database may disappear (taking the checkpoint with it) while we reboot the client. client.internals.disableDBCloseOnStop() // Otherwise the in-memory database may disappear (taking the checkpoint with it) while we reboot the client.
@ -161,7 +162,7 @@ class AttachmentSerializationTest {
private fun rebootClientAndGetAttachmentContent(checkAttachmentsOnLoad: Boolean = true): String { private fun rebootClientAndGetAttachmentContent(checkAttachmentsOnLoad: Boolean = true): String {
client.dispose() client.dispose()
client = mockNet.createNode(MockNodeParameters(client.internals.id, client.internals.configuration.myLegalName), { args -> client = mockNet.createNode(MockNodeParameters(client.internals.id, client.internals.configuration.myLegalName), { args ->
object : MockNetwork.MockNode(args) { object : InternalMockNetwork.MockNode(args) {
override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = checkAttachmentsOnLoad } override fun start() = super.start().apply { attachments.checkAttachmentsOnLoad = checkAttachmentsOnLoad }
} }
}) })

View File

@ -181,6 +181,9 @@ UNRELEASED
* Marked ``stateMachine`` on ``FlowLogic`` as ``CordaInternal`` to make clear that is it not part of the public api and is * Marked ``stateMachine`` on ``FlowLogic`` as ``CordaInternal`` to make clear that is it not part of the public api and is
only for internal use only for internal use
* Created new ``StartedMockNode`` and ``UnstartedMockNode`` classes which are wrappers around our MockNode implementation
that expose relevant methods for testing without exposing internals, create these using a ``MockNetwork``.
.. _changelog_v1: .. _changelog_v1:
Release 1.0 Release 1.0

View File

@ -1,5 +1,6 @@
package net.corda.docs package net.corda.docs
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.concurrent.transpose
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
@ -45,10 +46,10 @@ class IntegrationTestingTutorial {
// END 1 // END 1
// START 2 // START 2
val aliceClient = alice.rpcClientToNode() val aliceClient = CordaRPCClient(alice.rpcAddress)
val aliceProxy = aliceClient.start("aliceUser", "testPassword1").proxy val aliceProxy = aliceClient.start("aliceUser", "testPassword1").proxy
val bobClient = bob.rpcClientToNode() val bobClient = CordaRPCClient(bob.rpcAddress)
val bobProxy = bobClient.start("bobUser", "testPassword2").proxy val bobProxy = bobClient.start("bobUser", "testPassword2").proxy
// END 2 // END 2

View File

@ -2,6 +2,7 @@
package net.corda.docs package net.corda.docs
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
@ -53,7 +54,7 @@ fun main(args: Array<String>) {
// END 1 // END 1
// START 2 // START 2
val client = node.rpcClientToNode() val client = CordaRPCClient(node.rpcAddress)
val proxy = client.start("user", "password").proxy val proxy = client.start("user", "password").proxy
thread { thread {

View File

@ -13,15 +13,10 @@ import net.corda.core.serialization.serialize
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.node.internal.StartedNode
import net.corda.node.services.messaging.Message import net.corda.node.services.messaging.Message
import net.corda.node.services.statemachine.DataSessionMessage import net.corda.node.services.statemachine.DataSessionMessage
import net.corda.node.services.statemachine.ExistingSessionMessage import net.corda.node.services.statemachine.ExistingSessionMessage
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.*
import net.corda.testing.node.MessagingServiceSpy
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.setMessagingServiceSpy
import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
@ -58,8 +53,8 @@ class TutorialMockNetwork {
} }
lateinit private var mockNet: MockNetwork lateinit private var mockNet: MockNetwork
lateinit private var nodeA: StartedNode<MockNetwork.MockNode> lateinit private var nodeA: StartedMockNode
lateinit private var nodeB: StartedNode<MockNetwork.MockNode> lateinit private var nodeB: StartedMockNode
@Rule @Rule
@JvmField @JvmField

View File

@ -7,9 +7,9 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.* import net.corda.finance.*
import net.corda.finance.contracts.getCashBalances import net.corda.finance.contracts.getCashBalances
import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.StartedNode
import net.corda.testing.core.chooseIdentity import net.corda.testing.core.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Assert import org.junit.Assert
@ -19,8 +19,8 @@ import java.util.*
class CustomVaultQueryTest { class CustomVaultQueryTest {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var nodeA: StartedNode<MockNetwork.MockNode> private lateinit var nodeA: StartedMockNode
private lateinit var nodeB: StartedNode<MockNetwork.MockNode> private lateinit var nodeB: StartedMockNode
private lateinit var notary: Party private lateinit var notary: Party
@Before @Before

View File

@ -7,9 +7,9 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.* import net.corda.finance.*
import net.corda.finance.contracts.getCashBalances import net.corda.finance.contracts.getCashBalances
import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.StartedNode
import net.corda.testing.core.chooseIdentity import net.corda.testing.core.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -18,8 +18,8 @@ import kotlin.test.assertEquals
class FxTransactionBuildTutorialTest { class FxTransactionBuildTutorialTest {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var nodeA: StartedNode<MockNetwork.MockNode> private lateinit var nodeA: StartedMockNode
private lateinit var nodeB: StartedNode<MockNetwork.MockNode> private lateinit var nodeB: StartedMockNode
private lateinit var notary: Party private lateinit var notary: Party
@Before @Before

View File

@ -6,11 +6,10 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS import net.corda.finance.DOLLARS
import net.corda.finance.`issued by` import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.node.internal.StartedNode
import net.corda.testing.core.BOC_NAME import net.corda.testing.core.BOC_NAME
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.StartedMockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -22,7 +21,7 @@ class CashExitFlowTests {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private val initialBalance = 2000.DOLLARS private val initialBalance = 2000.DOLLARS
private val ref = OpaqueBytes.of(0x01) private val ref = OpaqueBytes.of(0x01)
private lateinit var bankOfCordaNode: StartedNode<MockNode> private lateinit var bankOfCordaNode: StartedMockNode
private lateinit var bankOfCorda: Party private lateinit var bankOfCorda: Party
private lateinit var notary: Party private lateinit var notary: Party

View File

@ -6,11 +6,10 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS import net.corda.finance.DOLLARS
import net.corda.finance.`issued by` import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.node.internal.StartedNode
import net.corda.testing.core.BOC_NAME import net.corda.testing.core.BOC_NAME
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.StartedMockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -20,7 +19,7 @@ import kotlin.test.assertFailsWith
class CashIssueFlowTests { class CashIssueFlowTests {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var bankOfCordaNode: StartedNode<MockNode> private lateinit var bankOfCordaNode: StartedMockNode
private lateinit var bankOfCorda: Party private lateinit var bankOfCorda: Party
private lateinit var notary: Party private lateinit var notary: Party

View File

@ -9,11 +9,10 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS import net.corda.finance.DOLLARS
import net.corda.finance.`issued by` import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.node.internal.StartedNode
import net.corda.testing.core.* import net.corda.testing.core.*
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.StartedMockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -25,9 +24,9 @@ class CashPaymentFlowTests {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private val initialBalance = 2000.DOLLARS private val initialBalance = 2000.DOLLARS
private val ref = OpaqueBytes.of(0x01) private val ref = OpaqueBytes.of(0x01)
private lateinit var bankOfCordaNode: StartedNode<MockNode> private lateinit var bankOfCordaNode: StartedMockNode
private lateinit var bankOfCorda: Party private lateinit var bankOfCorda: Party
private lateinit var aliceNode: StartedNode<MockNode> private lateinit var aliceNode: StartedMockNode
@Before @Before
fun start() { fun start() {

View File

@ -1,6 +1,7 @@
package net.corda.node package net.corda.node
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.div import net.corda.core.internal.div
@ -25,7 +26,7 @@ class BootTests {
fun `java deserialization is disabled`() { fun `java deserialization is disabled`() {
driver { driver {
val user = User("u", "p", setOf(startFlow<ObjectInputStreamFlow>())) val user = User("u", "p", setOf(startFlow<ObjectInputStreamFlow>()))
val future = startNode(rpcUsers = listOf(user)).getOrThrow().rpcClientToNode(). val future = CordaRPCClient(startNode(rpcUsers = listOf(user)).getOrThrow().rpcAddress).
start(user.username, user.password).proxy.startFlow(::ObjectInputStreamFlow).returnValue start(user.username, user.password).proxy.startFlow(::ObjectInputStreamFlow).returnValue
assertThatThrownBy { future.getOrThrow() }.isInstanceOf(InvalidClassException::class.java).hasMessage("filter status: REJECTED") assertThatThrownBy { future.getOrThrow() }.isInstanceOf(InvalidClassException::class.java).hasMessage("filter status: REJECTED")
} }
@ -37,7 +38,7 @@ class BootTests {
assertThat(logConfigFile).isRegularFile() assertThat(logConfigFile).isRegularFile()
driver(isDebug = true, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString())) { driver(isDebug = true, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString())) {
val alice = startNode(providedName = ALICE_NAME).get() val alice = startNode(providedName = ALICE_NAME).get()
val logFolder = alice.configuration.baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME val logFolder = alice.baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME
val logFile = logFolder.toFile().listFiles { _, name -> name.endsWith(".log") }.single() val logFile = logFolder.toFile().listFiles { _, name -> name.endsWith(".log") }.single()
// Start second Alice, should fail // Start second Alice, should fail
assertThatThrownBy { assertThatThrownBy {

View File

@ -1,6 +1,7 @@
package net.corda.node package net.corda.node
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.concurrent.transpose
@ -25,7 +26,7 @@ class CordappScanningDriverTest {
val (alice, bob) = listOf( val (alice, bob) = listOf(
startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)), startNode(providedName = ALICE_NAME, rpcUsers = listOf(user)),
startNode(providedName = BOB_NAME)).transpose().getOrThrow() startNode(providedName = BOB_NAME)).transpose().getOrThrow()
val initiatedFlowClass = alice.rpcClientToNode() val initiatedFlowClass = CordaRPCClient(alice.rpcAddress)
.start(user.username, user.password) .start(user.username, user.password)
.proxy .proxy
.startFlow(::ReceiveFlow, bob.nodeInfo.chooseIdentity()) .startFlow(::ReceiveFlow, bob.nodeInfo.chooseIdentity())

View File

@ -2,6 +2,7 @@ package net.corda.node
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import com.google.common.base.Stopwatch import com.google.common.base.Stopwatch
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StartableByRPC import net.corda.core.flows.StartableByRPC
import net.corda.core.internal.concurrent.transpose import net.corda.core.internal.concurrent.transpose
@ -14,19 +15,18 @@ import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.Permissions.Companion.startFlow import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.driver.InProcess
import net.corda.testing.node.User import net.corda.testing.node.User
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.internal.performance.div import net.corda.testing.internal.performance.div
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import net.corda.testing.node.internal.InternalDriverDSL import net.corda.testing.node.internal.InternalDriverDSL
import net.corda.testing.node.internal.internalDriver
import net.corda.testing.node.internal.performance.startPublishingFixedRateInjector import net.corda.testing.node.internal.performance.startPublishingFixedRateInjector
import net.corda.testing.node.internal.performance.startReporter import net.corda.testing.node.internal.performance.startReporter
import net.corda.testing.node.internal.performance.startTightLoopInjector import net.corda.testing.node.internal.performance.startTightLoopInjector
import org.junit.Before
import org.junit.Ignore import org.junit.Ignore
import org.junit.Test import org.junit.Test
import java.lang.management.ManagementFactory
import java.util.* import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.streams.toList import kotlin.streams.toList
@ -50,7 +50,7 @@ class NodePerformanceTests {
driver(startNodesInProcess = true) { driver(startNodesInProcess = true) {
val a = startNode(rpcUsers = listOf(User("A", "A", setOf(startFlow<EmptyFlow>())))).get() val a = startNode(rpcUsers = listOf(User("A", "A", setOf(startFlow<EmptyFlow>())))).get()
a.rpcClientToNode().use("A", "A") { connection -> CordaRPCClient(a.rpcAddress).use("A", "A") { connection ->
val timings = Collections.synchronizedList(ArrayList<Long>()) val timings = Collections.synchronizedList(ArrayList<Long>())
val N = 10000 val N = 10000
val overallTiming = Stopwatch.createStarted().apply { val overallTiming = Stopwatch.createStarted().apply {
@ -77,11 +77,11 @@ class NodePerformanceTests {
@Test @Test
fun `empty flow rate`() { fun `empty flow rate`() {
driver(startNodesInProcess = true) { internalDriver(startNodesInProcess = true) {
val a = startNode(rpcUsers = listOf(User("A", "A", setOf(startFlow<EmptyFlow>())))).get() val a = startNode(rpcUsers = listOf(User("A", "A", setOf(startFlow<EmptyFlow>())))).get()
a as NodeHandle.InProcess a as InProcess
val metricRegistry = startReporter((this as InternalDriverDSL).shutdownManager, a.node.services.monitoringService.metrics) val metricRegistry = startReporter(this.shutdownManager, a.services.monitoringService.metrics)
a.rpcClientToNode().use("A", "A") { connection -> CordaRPCClient(a.rpcAddress).use("A", "A") { connection ->
startPublishingFixedRateInjector(metricRegistry, 8, 5.minutes, 2000L / TimeUnit.SECONDS) { startPublishingFixedRateInjector(metricRegistry, 8, 5.minutes, 2000L / TimeUnit.SECONDS) {
connection.proxy.startFlow(::EmptyFlow).returnValue.get() connection.proxy.startFlow(::EmptyFlow).returnValue.get()
} }
@ -92,14 +92,14 @@ class NodePerformanceTests {
@Test @Test
fun `self pay rate`() { fun `self pay rate`() {
val user = User("A", "A", setOf(startFlow<CashIssueFlow>(), startFlow<CashPaymentFlow>())) val user = User("A", "A", setOf(startFlow<CashIssueFlow>(), startFlow<CashPaymentFlow>()))
driver( internalDriver(
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, rpcUsers = listOf(user))), notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, rpcUsers = listOf(user))),
startNodesInProcess = true, startNodesInProcess = true,
extraCordappPackagesToScan = listOf("net.corda.finance") extraCordappPackagesToScan = listOf("net.corda.finance")
) { ) {
val notary = defaultNotaryNode.getOrThrow() as NodeHandle.InProcess val notary = defaultNotaryNode.getOrThrow() as InProcess
val metricRegistry = startReporter((this as InternalDriverDSL).shutdownManager, notary.node.services.monitoringService.metrics) val metricRegistry = startReporter(this.shutdownManager, notary.services.monitoringService.metrics)
notary.rpcClientToNode().use("A", "A") { connection -> CordaRPCClient(notary.rpcAddress).use("A", "A") { connection ->
println("ISSUING") println("ISSUING")
val doneFutures = (1..100).toList().parallelStream().map { val doneFutures = (1..100).toList().parallelStream().map {
connection.proxy.startFlow(::CashIssueFlow, 1.DOLLARS, OpaqueBytes.of(0), defaultNotaryIdentity).returnValue connection.proxy.startFlow(::CashIssueFlow, 1.DOLLARS, OpaqueBytes.of(0), defaultNotaryIdentity).returnValue

View File

@ -18,7 +18,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.Try import net.corda.core.utilities.Try
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.BFTSMaRtConfiguration import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NotaryConfig import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.transactions.minClusterSize import net.corda.node.services.transactions.minClusterSize
@ -31,7 +30,7 @@ import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.dummyCommand import net.corda.testing.core.dummyCommand
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode import net.corda.testing.node.StartedMockNode
import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
@ -44,7 +43,7 @@ import kotlin.test.assertTrue
class BFTNotaryServiceTests { class BFTNotaryServiceTests {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var node: StartedNode<MockNode> private lateinit var node: StartedMockNode
@Before @Before
fun before() { fun before() {
@ -154,7 +153,7 @@ class BFTNotaryServiceTests {
} }
} }
private fun StartedNode<*>.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction { private fun StartedMockNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction( return services.signInitialTransaction(
TransactionBuilder(notary).apply { TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.chooseIdentity().owningKey)) addCommand(dummyCommand(services.myInfo.chooseIdentity().owningKey))

View File

@ -1,5 +1,6 @@
package net.corda.node.services package net.corda.node.services
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.internal.bufferUntilSubscribed import net.corda.core.internal.bufferUntilSubscribed
@ -15,6 +16,7 @@ import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.OutOfProcess
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import net.corda.testing.node.User import net.corda.testing.node.User
@ -26,7 +28,7 @@ import java.util.*
class DistributedServiceTests { class DistributedServiceTests {
private lateinit var alice: NodeHandle private lateinit var alice: NodeHandle
private lateinit var notaryNodes: List<NodeHandle.OutOfProcess> private lateinit var notaryNodes: List<OutOfProcess>
private lateinit var aliceProxy: CordaRPCOps private lateinit var aliceProxy: CordaRPCOps
private lateinit var raftNotaryIdentity: Party private lateinit var raftNotaryIdentity: Party
private lateinit var notaryStateMachines: Observable<Pair<Party, StateMachineUpdate>> private lateinit var notaryStateMachines: Observable<Pair<Party, StateMachineUpdate>>
@ -49,7 +51,7 @@ class DistributedServiceTests {
) { ) {
alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(testUser)).getOrThrow() alice = startNode(providedName = ALICE_NAME, rpcUsers = listOf(testUser)).getOrThrow()
raftNotaryIdentity = defaultNotaryIdentity raftNotaryIdentity = defaultNotaryIdentity
notaryNodes = defaultNotaryHandle.nodeHandles.getOrThrow().map { it as NodeHandle.OutOfProcess } notaryNodes = defaultNotaryHandle.nodeHandles.getOrThrow().map { it as OutOfProcess }
assertThat(notaryNodes).hasSize(3) assertThat(notaryNodes).hasSize(3)
@ -62,7 +64,7 @@ class DistributedServiceTests {
// Connect to Alice and the notaries // Connect to Alice and the notaries
fun connectRpc(node: NodeHandle): CordaRPCOps { fun connectRpc(node: NodeHandle): CordaRPCOps {
val client = node.rpcClientToNode() val client = CordaRPCClient(node.rpcAddress)
return client.start("test", "test").proxy return client.start("test", "test").proxy
} }
aliceProxy = connectRpc(alice) aliceProxy = connectRpc(alice)

View File

@ -10,13 +10,12 @@ import net.corda.core.identity.Party
import net.corda.core.internal.concurrent.map import net.corda.core.internal.concurrent.map
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.core.chooseIdentity import net.corda.testing.core.chooseIdentity
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.core.dummyCommand import net.corda.testing.core.dummyCommand
import net.corda.testing.driver.InProcess
import net.corda.testing.node.ClusterSpec import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
@ -35,7 +34,7 @@ class RaftNotaryServiceTests {
extraCordappPackagesToScan = listOf("net.corda.testing.contracts"), extraCordappPackagesToScan = listOf("net.corda.testing.contracts"),
notarySpecs = listOf(NotarySpec(notaryName, cluster = ClusterSpec.Raft(clusterSize = 3))) notarySpecs = listOf(NotarySpec(notaryName, cluster = ClusterSpec.Raft(clusterSize = 3)))
) { ) {
val bankA = startNode(providedName = DUMMY_BANK_A_NAME).map { (it as NodeHandle.InProcess).node }.getOrThrow() val bankA = startNode(providedName = DUMMY_BANK_A_NAME).map { (it as InProcess) }.getOrThrow()
val inputState = issueState(bankA, defaultNotaryIdentity) val inputState = issueState(bankA, defaultNotaryIdentity)
val firstTxBuilder = TransactionBuilder(defaultNotaryIdentity) val firstTxBuilder = TransactionBuilder(defaultNotaryIdentity)
@ -47,7 +46,7 @@ class RaftNotaryServiceTests {
firstSpend.getOrThrow() firstSpend.getOrThrow()
val secondSpendBuilder = TransactionBuilder(defaultNotaryIdentity).withItems(inputState).run { val secondSpendBuilder = TransactionBuilder(defaultNotaryIdentity).withItems(inputState).run {
val dummyState = DummyContract.SingleOwnerState(0, bankA.info.chooseIdentity()) val dummyState = DummyContract.SingleOwnerState(0, bankA.services.myInfo.chooseIdentity())
addOutputState(dummyState, DummyContract.PROGRAM_ID) addOutputState(dummyState, DummyContract.PROGRAM_ID)
addCommand(dummyCommand(bankA.services.myInfo.chooseIdentity().owningKey)) addCommand(dummyCommand(bankA.services.myInfo.chooseIdentity().owningKey))
this this
@ -61,11 +60,12 @@ class RaftNotaryServiceTests {
} }
} }
private fun issueState(node: StartedNode<*>, notary: Party): StateAndRef<*> { private fun issueState(nodeHandle: InProcess, notary: Party): StateAndRef<*> {
return node.database.transaction { return nodeHandle.database.transaction {
val builder = DummyContract.generateInitial(Random().nextInt(), notary, node.info.chooseIdentity().ref(0))
val stx = node.services.signInitialTransaction(builder) val builder = DummyContract.generateInitial(Random().nextInt(), notary, nodeHandle.services.myInfo.chooseIdentity().ref(0))
node.services.recordTransactions(stx) val stx = nodeHandle.services.signInitialTransaction(builder)
nodeHandle.services.recordTransactions(stx)
StateAndRef(builder.outputStates().first(), StateRef(stx.id, 0)) StateAndRef(builder.outputStates().first(), StateRef(stx.id, 0))
} }
} }

View File

@ -63,7 +63,7 @@ class NetworkMapTest {
notarySpecs = emptyList() notarySpecs = emptyList()
) { ) {
val alice = startNode(providedName = ALICE_NAME).getOrThrow() val alice = startNode(providedName = ALICE_NAME).getOrThrow()
val networkParameters = (alice.configuration.baseDirectory / NETWORK_PARAMS_FILE_NAME) val networkParameters = (alice.baseDirectory / NETWORK_PARAMS_FILE_NAME)
.readAll() .readAll()
.deserialize<SignedDataWithCert<NetworkParameters>>() .deserialize<SignedDataWithCert<NetworkParameters>>()
.verified() .verified()
@ -147,7 +147,7 @@ class NetworkMapTest {
private fun NodeHandle.onlySees(vararg nodes: NodeInfo) { private fun NodeHandle.onlySees(vararg nodes: NodeInfo) {
// Make sure the nodes aren't getting the node infos from their additional directories // Make sure the nodes aren't getting the node infos from their additional directories
val nodeInfosDir = configuration.baseDirectory / CordformNode.NODE_INFO_DIRECTORY val nodeInfosDir = baseDirectory / CordformNode.NODE_INFO_DIRECTORY
if (nodeInfosDir.exists()) { if (nodeInfosDir.exists()) {
assertThat(nodeInfosDir.list { it.toList() }).isEmpty() assertThat(nodeInfosDir.list { it.toList() }).isEmpty()
} }

View File

@ -1,5 +1,6 @@
package net.corda.node.services.rpc package net.corda.node.services.rpc
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.node.services.Permissions.Companion.all import net.corda.node.services.Permissions.Companion.all
@ -32,7 +33,7 @@ class RpcSslTest {
var successful = false var successful = false
driver(isDebug = true, startNodesInProcess = true, portAllocation = PortAllocation.RandomFree) { driver(isDebug = true, startNodesInProcess = true, portAllocation = PortAllocation.RandomFree) {
startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node -> startNode(rpcUsers = listOf(user), customOverrides = nodeSslOptions.useSslRpcOverrides()).getOrThrow().use { node ->
node.rpcClientToNode(clientSslOptions).start(user.username, user.password).use { connection -> CordaRPCClient(node.rpcAddress, sslConfiguration = clientSslOptions).start(user.username, user.password).use { connection ->
connection.proxy.apply { connection.proxy.apply {
nodeInfo() nodeInfo()
successful = true successful = true
@ -51,7 +52,7 @@ class RpcSslTest {
var successful = false var successful = false
driver(isDebug = true, startNodesInProcess = true, portAllocation = PortAllocation.RandomFree) { driver(isDebug = true, startNodesInProcess = true, portAllocation = PortAllocation.RandomFree) {
startNode(rpcUsers = listOf(user)).getOrThrow().use { node -> startNode(rpcUsers = listOf(user)).getOrThrow().use { node ->
node.rpcClientToNode().start(user.username, user.password).use { connection -> CordaRPCClient(node.rpcAddress).start(user.username, user.password).use { connection ->
connection.proxy.apply { connection.proxy.apply {
nodeInfo() nodeInfo()
successful = true successful = true

View File

@ -1,6 +1,7 @@
package net.corda.node.services.statemachine package net.corda.node.services.statemachine
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.internal.InputStreamAndHash import net.corda.core.internal.InputStreamAndHash
@ -73,7 +74,7 @@ class LargeTransactionsTest {
driver(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.testing.contracts"), portAllocation = PortAllocation.RandomFree) { driver(startNodesInProcess = true, extraCordappPackagesToScan = listOf("net.corda.testing.contracts"), portAllocation = PortAllocation.RandomFree) {
val rpcUser = User("admin", "admin", setOf("ALL")) val rpcUser = User("admin", "admin", setOf("ALL"))
val (alice, _) = listOf(ALICE_NAME, BOB_NAME).map { startNode(providedName = it, rpcUsers = listOf(rpcUser)) }.transpose().getOrThrow() val (alice, _) = listOf(ALICE_NAME, BOB_NAME).map { startNode(providedName = it, rpcUsers = listOf(rpcUser)) }.transpose().getOrThrow()
alice.rpcClientToNode().use(rpcUser.username, rpcUser.password) { CordaRPCClient(alice.rpcAddress).use(rpcUser.username, rpcUser.password) {
val hash1 = it.proxy.uploadAttachment(bigFile1.inputStream) val hash1 = it.proxy.uploadAttachment(bigFile1.inputStream)
val hash2 = it.proxy.uploadAttachment(bigFile2.inputStream) val hash2 = it.proxy.uploadAttachment(bigFile2.inputStream)
val hash3 = it.proxy.uploadAttachment(bigFile3.inputStream) val hash3 = it.proxy.uploadAttachment(bigFile3.inputStream)

View File

@ -12,15 +12,13 @@ import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize import net.corda.core.serialization.serialize
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.services.messaging.MessagingService import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.messaging.ReceivedMessage import net.corda.node.services.messaging.ReceivedMessage
import net.corda.node.services.messaging.send import net.corda.node.services.messaging.send
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.chooseIdentity import net.corda.testing.core.chooseIdentity
import net.corda.testing.driver.DriverDSL import net.corda.testing.driver.DriverDSL
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.InProcess
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.node.ClusterSpec import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
@ -44,13 +42,14 @@ class P2PMessagingTest {
} }
} }
@Test @Test
fun `distributed service requests are retried if one of the nodes in the cluster goes down without sending a response`() { fun `distributed service requests are retried if one of the nodes in the cluster goes down without sending a response`() {
startDriverWithDistributedService { distributedServiceNodes -> startDriverWithDistributedService { distributedServiceNodes ->
val alice = startAlice() val alice = startAlice()
val serviceAddress = alice.services.networkMapCache.run { val serviceAddress = alice.services.networkMapCache.run {
val notaryParty = notaryIdentities.randomOrNull()!! val notaryParty = notaryIdentities.randomOrNull()!!
alice.network.getAddressOfParty(getPartyInfo(notaryParty)!!) alice.services.networkService.getAddressOfParty(getPartyInfo(notaryParty)!!)
} }
val responseMessage = "response" val responseMessage = "response"
@ -76,7 +75,7 @@ class P2PMessagingTest {
val alice = startAlice() val alice = startAlice()
val serviceAddress = alice.services.networkMapCache.run { val serviceAddress = alice.services.networkMapCache.run {
val notaryParty = notaryIdentities.randomOrNull()!! val notaryParty = notaryIdentities.randomOrNull()!!
alice.network.getAddressOfParty(getPartyInfo(notaryParty)!!) alice.services.networkService.getAddressOfParty(getPartyInfo(notaryParty)!!)
} }
val responseMessage = "response" val responseMessage = "response"
@ -89,7 +88,7 @@ class P2PMessagingTest {
// Wait until the first request is received // Wait until the first request is received
crashingNodes.firstRequestReceived.await() crashingNodes.firstRequestReceived.await()
// Stop alice's node after we ensured that the first request was delivered and ignored. // Stop alice's node after we ensured that the first request was delivered and ignored.
alice.dispose() alice.stop()
val numberOfRequestsReceived = crashingNodes.requestsReceived.get() val numberOfRequestsReceived = crashingNodes.requestsReceived.get()
assertThat(numberOfRequestsReceived).isGreaterThanOrEqualTo(1) assertThat(numberOfRequestsReceived).isGreaterThanOrEqualTo(1)
@ -99,7 +98,7 @@ class P2PMessagingTest {
val aliceRestarted = startAlice() val aliceRestarted = startAlice()
val responseFuture = openFuture<Any>() val responseFuture = openFuture<Any>()
aliceRestarted.network.runOnNextMessage("test.response") { aliceRestarted.services.networkService.runOnNextMessage("test.response") {
responseFuture.set(it.data.deserialize()) responseFuture.set(it.data.deserialize())
} }
val response = responseFuture.getOrThrow() val response = responseFuture.getOrThrow()
@ -109,15 +108,16 @@ class P2PMessagingTest {
} }
} }
private fun startDriverWithDistributedService(dsl: DriverDSL.(List<StartedNode<Node>>) -> Unit) {
private fun startDriverWithDistributedService(dsl: DriverDSL.(List<InProcess>) -> Unit) {
driver(startNodesInProcess = true, notarySpecs = listOf(NotarySpec(DISTRIBUTED_SERVICE_NAME, cluster = ClusterSpec.Raft(clusterSize = 2)))) { driver(startNodesInProcess = true, notarySpecs = listOf(NotarySpec(DISTRIBUTED_SERVICE_NAME, cluster = ClusterSpec.Raft(clusterSize = 2)))) {
dsl(defaultNotaryHandle.nodeHandles.getOrThrow().map { (it as NodeHandle.InProcess).node }) dsl(defaultNotaryHandle.nodeHandles.getOrThrow().map { (it as InProcess) })
} }
} }
private fun DriverDSL.startAlice(): StartedNode<Node> { private fun DriverDSL.startAlice(): InProcess {
return startNode(providedName = ALICE_NAME, customOverrides = mapOf("messageRedeliveryDelaySeconds" to 1)) return startNode(providedName = ALICE_NAME, customOverrides = mapOf("messageRedeliveryDelaySeconds" to 1))
.map { (it as NodeHandle.InProcess).node } .map { (it as InProcess) }
.getOrThrow() .getOrThrow()
} }
@ -133,7 +133,7 @@ class P2PMessagingTest {
* initially set to true. This may be used to simulate scenarios where nodes receive request messages but crash * initially set to true. This may be used to simulate scenarios where nodes receive request messages but crash
* before sending back a response. * before sending back a response.
*/ */
private fun simulateCrashingNodes(distributedServiceNodes: List<StartedNode<*>>, responseMessage: String): CrashingNodes { private fun simulateCrashingNodes(distributedServiceNodes: List<InProcess>, responseMessage: String): CrashingNodes {
val crashingNodes = CrashingNodes( val crashingNodes = CrashingNodes(
requestsReceived = AtomicInteger(0), requestsReceived = AtomicInteger(0),
firstRequestReceived = CountDownLatch(1), firstRequestReceived = CountDownLatch(1),
@ -141,8 +141,8 @@ class P2PMessagingTest {
) )
distributedServiceNodes.forEach { distributedServiceNodes.forEach {
val nodeName = it.info.chooseIdentity().name val nodeName = it.services.myInfo.chooseIdentity().name
it.network.addMessageHandler("test.request") { netMessage, _ -> it.services.networkService.addMessageHandler("test.request") { netMessage, _ ->
crashingNodes.requestsReceived.incrementAndGet() crashingNodes.requestsReceived.incrementAndGet()
crashingNodes.firstRequestReceived.countDown() crashingNodes.firstRequestReceived.countDown()
// The node which receives the first request will ignore all requests // The node which receives the first request will ignore all requests
@ -154,21 +154,21 @@ class P2PMessagingTest {
} else { } else {
println("sending response") println("sending response")
val request = netMessage.data.deserialize<TestRequest>() val request = netMessage.data.deserialize<TestRequest>()
val response = it.network.createMessage("test.response", responseMessage.serialize().bytes) val response = it.services.networkService.createMessage("test.response", responseMessage.serialize().bytes)
it.network.send(response, request.replyTo) it.services.networkService.send(response, request.replyTo)
} }
} }
} }
return crashingNodes return crashingNodes
} }
private fun assertAllNodesAreUsed(participatingServiceNodes: List<StartedNode<*>>, serviceName: CordaX500Name, originatingNode: StartedNode<*>) { private fun assertAllNodesAreUsed(participatingServiceNodes: List<InProcess>, serviceName: CordaX500Name, originatingNode: InProcess) {
// Setup each node in the distributed service to return back it's NodeInfo so that we can know which node is being used // Setup each node in the distributed service to return back it's NodeInfo so that we can know which node is being used
participatingServiceNodes.forEach { node -> participatingServiceNodes.forEach { node ->
node.respondWith(node.info) node.respondWith(node.services.myInfo)
} }
val serviceAddress = originatingNode.services.networkMapCache.run { val serviceAddress = originatingNode.services.networkMapCache.run {
originatingNode.network.getAddressOfParty(getPartyInfo(getNotary(serviceName)!!)!!) originatingNode.services.networkService.getAddressOfParty(getPartyInfo(getNotary(serviceName)!!)!!)
} }
val participatingNodes = HashSet<Any>() val participatingNodes = HashSet<Any>()
// Try several times so that we can be fairly sure that any node not participating is not due to Artemis' selection // Try several times so that we can be fairly sure that any node not participating is not due to Artemis' selection
@ -180,23 +180,23 @@ class P2PMessagingTest {
break break
} }
} }
assertThat(participatingNodes).containsOnlyElementsOf(participatingServiceNodes.map(StartedNode<*>::info)) assertThat(participatingNodes).containsOnlyElementsOf(participatingServiceNodes.map { it.services.myInfo })
} }
private fun StartedNode<*>.respondWith(message: Any) { private fun InProcess.respondWith(message: Any) {
network.addMessageHandler("test.request") { netMessage, _ -> services.networkService.addMessageHandler("test.request") { netMessage, _ ->
val request = netMessage.data.deserialize<TestRequest>() val request = netMessage.data.deserialize<TestRequest>()
val response = network.createMessage("test.response", message.serialize().bytes) val response = services.networkService.createMessage("test.response", message.serialize().bytes)
network.send(response, request.replyTo) services.networkService.send(response, request.replyTo)
} }
} }
private fun StartedNode<*>.receiveFrom(target: MessageRecipients, retryId: Long? = null): CordaFuture<Any> { private fun InProcess.receiveFrom(target: MessageRecipients, retryId: Long? = null): CordaFuture<Any> {
val response = openFuture<Any>() val response = openFuture<Any>()
network.runOnNextMessage("test.response") { netMessage -> services.networkService.runOnNextMessage("test.response") { netMessage ->
response.set(netMessage.data.deserialize()) response.set(netMessage.data.deserialize())
} }
network.send("test.request", TestRequest(replyTo = network.myAddress), target, retryId = retryId) services.networkService.send("test.request", TestRequest(replyTo = services.networkService.myAddress), target, retryId = retryId)
return response return response
} }

View File

@ -1,6 +1,7 @@
package net.corda.test.node package net.corda.test.node
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.* import net.corda.core.contracts.*
import net.corda.core.flows.FinalityFlow import net.corda.core.flows.FinalityFlow
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
@ -47,7 +48,7 @@ class NodeStatePersistenceTests {
val nodeName = nodeHandle.nodeInfo.chooseIdentity().name val nodeName = nodeHandle.nodeInfo.chooseIdentity().name
// Ensure the notary node has finished starting up, before starting a flow that needs a notary // Ensure the notary node has finished starting up, before starting a flow that needs a notary
defaultNotaryNode.getOrThrow() defaultNotaryNode.getOrThrow()
nodeHandle.rpcClientToNode().start(user.username, user.password).use { CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow() it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow()
} }
nodeHandle.stop() nodeHandle.stop()
@ -55,7 +56,7 @@ class NodeStatePersistenceTests {
}() }()
val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user)).getOrThrow() val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user)).getOrThrow()
val result = nodeHandle.rpcClientToNode().start(user.username, user.password).use { val result = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
val page = it.proxy.vaultQuery(MessageState::class.java) val page = it.proxy.vaultQuery(MessageState::class.java)
page.states.singleOrNull() page.states.singleOrNull()
} }
@ -81,7 +82,7 @@ class NodeStatePersistenceTests {
val nodeName = nodeHandle.nodeInfo.chooseIdentity().name val nodeName = nodeHandle.nodeInfo.chooseIdentity().name
// Ensure the notary node has finished starting up, before starting a flow that needs a notary // Ensure the notary node has finished starting up, before starting a flow that needs a notary
defaultNotaryNode.getOrThrow() defaultNotaryNode.getOrThrow()
nodeHandle.rpcClientToNode().start(user.username, user.password).use { CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow() it.proxy.startFlow(::SendMessageFlow, message, defaultNotaryIdentity).returnValue.getOrThrow()
} }
nodeHandle.stop() nodeHandle.stop()
@ -89,7 +90,7 @@ class NodeStatePersistenceTests {
}() }()
val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user), customOverrides = mapOf("devMode" to "false")).getOrThrow() val nodeHandle = startNode(providedName = nodeName, rpcUsers = listOf(user), customOverrides = mapOf("devMode" to "false")).getOrThrow()
val result = nodeHandle.rpcClientToNode().start(user.username, user.password).use { val result = CordaRPCClient(nodeHandle.rpcAddress).start(user.username, user.password).use {
val page = it.proxy.vaultQuery(MessageState::class.java) val page = it.proxy.vaultQuery(MessageState::class.java)
page.states.singleOrNull() page.states.singleOrNull()
} }

View File

@ -37,9 +37,9 @@ import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.expect import net.corda.testing.core.expect
import net.corda.testing.core.expectEvents import net.corda.testing.core.expectEvents
import net.corda.testing.core.sequence import net.corda.testing.core.sequence
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode
import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.testActor import net.corda.testing.node.testActor
import org.apache.commons.io.IOUtils import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatExceptionOfType
@ -68,7 +68,7 @@ class CordaRPCOpsImplTest {
val testJar = "net/corda/node/testing/test.jar" val testJar = "net/corda/node/testing/test.jar"
} }
private lateinit var mockNet: MockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode> private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var alice: Party private lateinit var alice: Party
private lateinit var notary: Party private lateinit var notary: Party
@ -79,7 +79,7 @@ class CordaRPCOpsImplTest {
@Before @Before
fun setup() { fun setup() {
mockNet = MockNetwork(cordappPackages = listOf("net.corda.finance.contracts.asset")) mockNet = InternalMockNetwork(cordappPackages = listOf("net.corda.finance.contracts.asset"))
aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME)) aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
rpc = SecureCordaRPCOps(aliceNode.services, aliceNode.smm, aliceNode.database, aliceNode.services) rpc = SecureCordaRPCOps(aliceNode.services, aliceNode.smm, aliceNode.database, aliceNode.services)
CURRENT_RPC_CONTEXT.set(RpcAuthContext(InvocationContext.rpc(testActor()), buildSubject("TEST_USER", emptySet()))) CURRENT_RPC_CONTEXT.set(RpcAuthContext(InvocationContext.rpc(testActor()), buildSubject("TEST_USER", emptySet())))

View File

@ -15,6 +15,7 @@ import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.cordapp.DummyRPCFlow import net.corda.node.internal.cordapp.DummyRPCFlow
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.StartedMockNode
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -75,7 +76,7 @@ class LegacyCordaService(@Suppress("UNUSED_PARAMETER") simpleServiceHub: Service
class CordaServiceTest { class CordaServiceTest {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var nodeA: StartedNode<MockNetwork.MockNode> private lateinit var nodeA: StartedMockNode
@Before @Before
fun start() { fun start() {

View File

@ -27,7 +27,7 @@ class NetworkParametersTest {
private val mockNet = MockNetwork( private val mockNet = MockNetwork(
emptyList(), emptyList(),
MockNetworkParameters(networkSendManuallyPumped = true), MockNetworkParameters(networkSendManuallyPumped = true),
notarySpecs = listOf(MockNetwork.NotarySpec(DUMMY_NOTARY_NAME))) notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME)))
@After @After
fun tearDown() { fun tearDown() {

View File

@ -48,6 +48,8 @@ import net.corda.testing.dsl.TestTransactionDSLInterpreter
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import net.corda.testing.internal.vault.VaultFiller import net.corda.testing.internal.vault.VaultFiller
import net.corda.testing.node.* import net.corda.testing.node.*
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.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
@ -83,7 +85,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private val DUMMY_NOTARY get() = dummyNotary.party private val DUMMY_NOTARY get() = dummyNotary.party
} }
private lateinit var mockNet: MockNetwork private lateinit var mockNet: InternalMockNetwork
@Before @Before
fun before() { fun before() {
@ -101,7 +103,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
// We run this in parallel threads to help catch any race conditions that may exist. The other tests // We run this in parallel threads to help catch any race conditions that may exist. The other tests
// we run in the unit test thread exclusively to speed things up, ensure deterministic results and // we run in the unit test thread exclusively to speed things up, ensure deterministic results and
// allow interruption half way through. // allow interruption half way through.
mockNet = MockNetwork(threadPerNode = true, cordappPackages = cordappPackages) mockNet = InternalMockNetwork(threadPerNode = true, cordappPackages = cordappPackages)
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>() val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) { MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) {
val notaryNode = mockNet.defaultNotaryNode val notaryNode = mockNet.defaultNotaryNode
@ -153,7 +155,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test(expected = InsufficientBalanceException::class) @Test(expected = InsufficientBalanceException::class)
fun `trade cash for commercial paper fails using soft locking`() { fun `trade cash for commercial paper fails using soft locking`() {
mockNet = MockNetwork(threadPerNode = true, cordappPackages = cordappPackages) mockNet = InternalMockNetwork(threadPerNode = true, cordappPackages = cordappPackages)
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>() val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) { MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) {
val notaryNode = mockNet.defaultNotaryNode val notaryNode = mockNet.defaultNotaryNode
@ -211,7 +213,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test @Test
fun `shutdown and restore`() { fun `shutdown and restore`() {
mockNet = MockNetwork(cordappPackages = cordappPackages) mockNet = InternalMockNetwork(cordappPackages = cordappPackages)
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>() val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) { MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) {
val notaryNode = mockNet.defaultNotaryNode val notaryNode = mockNet.defaultNotaryNode
@ -308,11 +310,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
// Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order // Creates a mock node with an overridden storage service that uses a RecordingMap, that lets us test the order
// of gets and puts. // of gets and puts.
private fun makeNodeWithTracking( private fun makeNodeWithTracking(name: CordaX500Name): StartedNode<InternalMockNetwork.MockNode> {
name: CordaX500Name): StartedNode<MockNetwork.MockNode> {
// Create a node in the mock network ... // Create a node in the mock network ...
return mockNet.createNode(MockNodeParameters(legalName = name), nodeFactory = { args -> return mockNet.createNode(MockNodeParameters(legalName = name), nodeFactory = { args ->
object : MockNetwork.MockNode(args) { object : InternalMockNetwork.MockNode(args) {
// That constructs a recording tx storage // That constructs a recording tx storage
override fun makeTransactionStorage(database: CordaPersistence, transactionCacheSizeBytes: Long): WritableTransactionStorage { override fun makeTransactionStorage(database: CordaPersistence, transactionCacheSizeBytes: Long): WritableTransactionStorage {
return RecordingTransactionStorage(database, super.makeTransactionStorage(database, transactionCacheSizeBytes)) return RecordingTransactionStorage(database, super.makeTransactionStorage(database, transactionCacheSizeBytes))
@ -323,7 +324,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test @Test
fun `check dependencies of sale asset are resolved`() { fun `check dependencies of sale asset are resolved`() {
mockNet = MockNetwork(cordappPackages = cordappPackages) mockNet = InternalMockNetwork(cordappPackages = cordappPackages)
val notaryNode = mockNet.defaultNotaryNode val notaryNode = mockNet.defaultNotaryNode
val aliceNode = makeNodeWithTracking(ALICE_NAME) val aliceNode = makeNodeWithTracking(ALICE_NAME)
val bobNode = makeNodeWithTracking(BOB_NAME) val bobNode = makeNodeWithTracking(BOB_NAME)
@ -427,7 +428,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test @Test
fun `track works`() { fun `track works`() {
mockNet = MockNetwork(cordappPackages = cordappPackages) mockNet = InternalMockNetwork(cordappPackages = cordappPackages)
val notaryNode = mockNet.defaultNotaryNode val notaryNode = mockNet.defaultNotaryNode
val aliceNode = makeNodeWithTracking(ALICE_NAME) val aliceNode = makeNodeWithTracking(ALICE_NAME)
val bobNode = makeNodeWithTracking(BOB_NAME) val bobNode = makeNodeWithTracking(BOB_NAME)
@ -505,7 +506,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test @Test
fun `dependency with error on buyer side`() { fun `dependency with error on buyer side`() {
mockNet = MockNetwork(cordappPackages = cordappPackages) mockNet = InternalMockNetwork(cordappPackages = cordappPackages)
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>() val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) { MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) {
runWithError(ledgerIdentityService, true, false, "at least one cash input") runWithError(ledgerIdentityService, true, false, "at least one cash input")
@ -514,7 +515,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
@Test @Test
fun `dependency with error on seller side`() { fun `dependency with error on seller side`() {
mockNet = MockNetwork(cordappPackages = cordappPackages) mockNet = InternalMockNetwork(cordappPackages = cordappPackages)
val ledgerIdentityService = rigorousMock<IdentityServiceInternal>() val ledgerIdentityService = rigorousMock<IdentityServiceInternal>()
MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) { MockServices(cordappPackages, ledgerIdentityService, MEGA_CORP.name).ledger(DUMMY_NOTARY) {
runWithError(ledgerIdentityService, false, true, "Issuances have a time-window") runWithError(ledgerIdentityService, false, true, "Issuances have a time-window")
@ -530,8 +531,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun runBuyerAndSeller(notary: Party, private fun runBuyerAndSeller(notary: Party,
buyer: Party, buyer: Party,
sellerNode: StartedNode<MockNetwork.MockNode>, sellerNode: StartedNode<InternalMockNetwork.MockNode>,
buyerNode: StartedNode<MockNetwork.MockNode>, buyerNode: StartedNode<InternalMockNetwork.MockNode>,
assetToSell: StateAndRef<OwnableState>): RunResult { assetToSell: StateAndRef<OwnableState>): RunResult {
val buyerFlows: Observable<out FlowLogic<*>> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java) val buyerFlows: Observable<out FlowLogic<*>> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java)
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine } val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }

View File

@ -12,13 +12,9 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.node.MockNetwork import net.corda.testing.node.*
import net.corda.testing.node.MockNetwork.NotarySpec
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.startFlow
import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -30,9 +26,9 @@ import kotlin.test.assertTrue
class NotaryChangeTests { class NotaryChangeTests {
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
private lateinit var oldNotaryNode: StartedNode<MockNetwork.MockNode> private lateinit var oldNotaryNode: StartedMockNode
private lateinit var clientNodeA: StartedNode<MockNetwork.MockNode> private lateinit var clientNodeA: StartedMockNode
private lateinit var clientNodeB: StartedNode<MockNetwork.MockNode> private lateinit var clientNodeB: StartedMockNode
private lateinit var newNotaryParty: Party private lateinit var newNotaryParty: Party
private lateinit var oldNotaryParty: Party private lateinit var oldNotaryParty: Party
private lateinit var clientA: Party private lateinit var clientA: Party
@ -41,7 +37,7 @@ class NotaryChangeTests {
fun setUp() { fun setUp() {
val oldNotaryName = CordaX500Name("Regulator A", "Paris", "FR") val oldNotaryName = CordaX500Name("Regulator A", "Paris", "FR")
mockNet = MockNetwork( mockNet = MockNetwork(
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME), NotarySpec(oldNotaryName)), notarySpecs = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME), MockNetworkNotarySpec(oldNotaryName)),
cordappPackages = listOf("net.corda.testing.contracts") cordappPackages = listOf("net.corda.testing.contracts")
) )
clientNodeA = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME)) clientNodeA = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
@ -145,7 +141,7 @@ class NotaryChangeTests {
assertEquals(issued.state, changedNotaryBack.state) assertEquals(issued.state, changedNotaryBack.state)
} }
private fun changeNotary(movedState: StateAndRef<DummyContract.SingleOwnerState>, node: StartedNode<*>, newNotary: Party): StateAndRef<DummyContract.SingleOwnerState> { private fun changeNotary(movedState: StateAndRef<DummyContract.SingleOwnerState>, node: StartedMockNode, newNotary: Party): StateAndRef<DummyContract.SingleOwnerState> {
val flow = NotaryChangeFlow(movedState, newNotary) val flow = NotaryChangeFlow(movedState, newNotary)
val future = node.services.startFlow(flow) val future = node.services.startFlow(flow)
mockNet.runNetwork() mockNet.runNetwork()
@ -153,7 +149,7 @@ class NotaryChangeTests {
return future.getOrThrow() return future.getOrThrow()
} }
private fun moveState(state: StateAndRef<DummyContract.SingleOwnerState>, fromNode: StartedNode<*>, toNode: StartedNode<*>): StateAndRef<DummyContract.SingleOwnerState> { private fun moveState(state: StateAndRef<DummyContract.SingleOwnerState>, fromNode: StartedMockNode, toNode: StartedMockNode): StateAndRef<DummyContract.SingleOwnerState> {
val tx = DummyContract.move(state, toNode.info.chooseIdentity()) val tx = DummyContract.move(state, toNode.info.chooseIdentity())
val stx = fromNode.services.signInitialTransaction(tx) val stx = fromNode.services.signInitialTransaction(tx)
@ -203,7 +199,7 @@ fun issueState(services: ServiceHub, nodeIdentity: Party, notaryIdentity: Party)
return stx.tx.outRef(0) return stx.tx.outRef(0)
} }
fun issueMultiPartyState(nodeA: StartedNode<*>, nodeB: StartedNode<*>, notaryNode: StartedNode<*>, notaryIdentity: Party): StateAndRef<DummyContract.MultiOwnerState> { fun issueMultiPartyState(nodeA: StartedMockNode, nodeB: StartedMockNode, notaryNode: StartedMockNode, notaryIdentity: Party): StateAndRef<DummyContract.MultiOwnerState> {
val participants = listOf(nodeA.info.chooseIdentity(), nodeB.info.chooseIdentity()) val participants = listOf(nodeA.info.chooseIdentity(), nodeB.info.chooseIdentity())
val state = TransactionState( val state = TransactionState(
DummyContract.MultiOwnerState(0, participants), DummyContract.MultiOwnerState(0, participants),

View File

@ -25,8 +25,9 @@ import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.BOB_NAME import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.dummyCommand import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Assert.* import org.junit.Assert.*
@ -42,9 +43,9 @@ class ScheduledFlowTests {
val SORTING = Sort(listOf(Sort.SortColumn(SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_TXN_ID), Sort.Direction.DESC))) val SORTING = Sort(listOf(Sort.SortColumn(SortAttribute.Standard(Sort.CommonStateAttribute.STATE_REF_TXN_ID), Sort.Direction.DESC)))
} }
private lateinit var mockNet: MockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNetwork.MockNode> private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNetwork.MockNode> private lateinit var bobNode: StartedNode<MockNode>
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var alice: Party private lateinit var alice: Party
private lateinit var bob: Party private lateinit var bob: Party
@ -102,7 +103,7 @@ class ScheduledFlowTests {
@Before @Before
fun setup() { fun setup() {
mockNet = MockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.testing.contracts")) mockNet = InternalMockNetwork(threadPerNode = true, cordappPackages = listOf("net.corda.testing.contracts"))
aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME)) aliceNode = mockNet.createNode(MockNodeParameters(legalName = ALICE_NAME))
bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME)) bobNode = mockNet.createNode(MockNodeParameters(legalName = BOB_NAME))
notary = mockNet.defaultNotaryIdentity notary = mockNet.defaultNotaryIdentity

View File

@ -11,7 +11,7 @@ import net.corda.core.utilities.getOrThrow
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.schema.NodeSchemaService.NodeCoreV1 import net.corda.node.services.schema.NodeSchemaService.NodeCoreV1
import net.corda.node.services.schema.NodeSchemaService.NodeNotaryV1 import net.corda.node.services.schema.NodeSchemaService.NodeNotaryV1
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.InProcess
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.internal.vault.DummyLinearStateSchemaV1 import net.corda.testing.internal.vault.DummyLinearStateSchemaV1
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
@ -26,7 +26,7 @@ import kotlin.test.assertTrue
class NodeSchemaServiceTest { class NodeSchemaServiceTest {
/** /**
* Note: this test requires explicitly registering custom contract schemas with a MockNode * Note: this test requires explicitly registering custom contract schemas with a StartedMockNode
*/ */
@Test @Test
fun `registering custom schemas for testing with MockNode`() { fun `registering custom schemas for testing with MockNode`() {
@ -79,7 +79,7 @@ class NodeSchemaServiceTest {
fun `custom schemas are loaded eagerly`() { fun `custom schemas are loaded eagerly`() {
val expected = setOf("PARENTS", "CHILDREN") val expected = setOf("PARENTS", "CHILDREN")
val tables = driver(startNodesInProcess = true) { val tables = driver(startNodesInProcess = true) {
(defaultNotaryNode.getOrThrow() as NodeHandle.InProcess).node.database.transaction { (defaultNotaryNode.getOrThrow() as InProcess).database.transaction {
session.createNativeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES").list() session.createNativeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES").list()
} }
} }

View File

@ -34,11 +34,11 @@ import net.corda.testing.core.*
import net.corda.testing.internal.LogHelper import net.corda.testing.internal.LogHelper
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer 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.MockNode
import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.pumpReceive
import net.corda.testing.node.internal.startFlow import net.corda.testing.node.internal.startFlow
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
import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType
@ -62,7 +62,7 @@ class FlowFrameworkTests {
} }
} }
private lateinit var mockNet: MockNetwork private lateinit var mockNet: InternalMockNetwork
private val receivedSessionMessages = ArrayList<SessionTransfer>() private val receivedSessionMessages = ArrayList<SessionTransfer>()
private lateinit var aliceNode: StartedNode<MockNode> private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode> private lateinit var bobNode: StartedNode<MockNode>
@ -76,7 +76,7 @@ class FlowFrameworkTests {
@Before @Before
fun start() { fun start() {
mockNet = MockNetwork( mockNet = InternalMockNetwork(
servicePeerAllocationStrategy = RoundRobin(), servicePeerAllocationStrategy = RoundRobin(),
cordappPackages = listOf("net.corda.finance.contracts", "net.corda.testing.contracts") cordappPackages = listOf("net.corda.finance.contracts", "net.corda.testing.contracts")
) )
@ -145,7 +145,7 @@ class FlowFrameworkTests {
val restoredFlow = bobNode.restartAndGetRestoredFlow<InitiatedReceiveFlow>() val restoredFlow = bobNode.restartAndGetRestoredFlow<InitiatedReceiveFlow>()
assertThat(restoredFlow.receivedPayloads[0]).isEqualTo("Hello") assertThat(restoredFlow.receivedPayloads[0]).isEqualTo("Hello")
} }
@Test @Test
fun `flow loaded from checkpoint will respond to messages from before start`() { fun `flow loaded from checkpoint will respond to messages from before start`() {
aliceNode.registerFlowFactory(ReceiveFlow::class) { InitiatedSendFlow("Hello", it) } aliceNode.registerFlowFactory(ReceiveFlow::class) { InitiatedSendFlow("Hello", it) }

View File

@ -30,6 +30,7 @@ import net.corda.testing.core.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.internal.rigorousMock import net.corda.testing.internal.rigorousMock
import net.corda.testing.node.MockNodeParameters import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.startFlow import net.corda.testing.node.startFlow
import org.junit.After import org.junit.After
import org.junit.Test import org.junit.Test
@ -38,7 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean
import kotlin.reflect.jvm.jvmName import kotlin.reflect.jvm.jvmName
import kotlin.test.assertEquals import kotlin.test.assertEquals
class NodePair(private val mockNet: MockNetwork) { class NodePair(private val mockNet: InternalMockNetwork) {
private class ServerLogic(private val session: FlowSession, private val running: AtomicBoolean) : FlowLogic<Unit>() { private class ServerLogic(private val session: FlowSession, private val running: AtomicBoolean) : FlowLogic<Unit>() {
@Suspendable @Suspendable
override fun call() { override fun call() {
@ -81,8 +82,8 @@ class VaultSoftLockManagerTest {
private val mockVault = rigorousMock<VaultServiceInternal>().also { private val mockVault = rigorousMock<VaultServiceInternal>().also {
doNothing().whenever(it).softLockRelease(any(), anyOrNull()) doNothing().whenever(it).softLockRelease(any(), anyOrNull())
} }
private val mockNet = MockNetwork(cordappPackages = listOf(ContractImpl::class.packageName), defaultFactory = { args -> private val mockNet = InternalMockNetwork(cordappPackages = listOf(ContractImpl::class.packageName), defaultFactory = { args ->
object : MockNetwork.MockNode(args) { object : InternalMockNetwork.MockNode(args) {
override fun makeVaultService(keyManagementService: KeyManagementService, stateLoader: StateLoader, hibernateConfig: HibernateConfiguration): VaultServiceInternal { override fun makeVaultService(keyManagementService: KeyManagementService, stateLoader: StateLoader, hibernateConfig: HibernateConfiguration): VaultServiceInternal {
val realVault = super.makeVaultService(keyManagementService, stateLoader, hibernateConfig) val realVault = super.makeVaultService(keyManagementService, stateLoader, hibernateConfig)
return object : VaultServiceInternal by realVault { return object : VaultServiceInternal by realVault {

View File

@ -1,5 +1,6 @@
package net.corda.attachmentdemo package net.corda.attachmentdemo
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.invokeRpc
@ -9,6 +10,7 @@ import net.corda.testing.core.DUMMY_BANK_B_NAME
import net.corda.testing.node.User import net.corda.testing.node.User
import net.corda.testing.driver.PortAllocation import net.corda.testing.driver.PortAllocation
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.driver.internal.NodeHandleInternal
import org.junit.Test import org.junit.Test
import java.util.concurrent.CompletableFuture.supplyAsync import java.util.concurrent.CompletableFuture.supplyAsync
@ -30,17 +32,17 @@ class AttachmentDemoTest {
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = demoUser, maximumHeapSize = "1g"),
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = demoUser, maximumHeapSize = "1g") startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = demoUser, maximumHeapSize = "1g")
).map { it.getOrThrow() } ).map { it.getOrThrow() }
startWebserver(nodeB).getOrThrow() val webserverHandle = startWebserver(nodeB).getOrThrow()
val senderThread = supplyAsync { val senderThread = supplyAsync {
nodeA.rpcClientToNode().start(demoUser[0].username, demoUser[0].password).use { CordaRPCClient(nodeA.rpcAddress).start(demoUser[0].username, demoUser[0].password).use {
sender(it.proxy, numOfExpectedBytes) sender(it.proxy, numOfExpectedBytes)
} }
} }
val recipientThread = supplyAsync { val recipientThread = supplyAsync {
nodeB.rpcClientToNode().start(demoUser[0].username, demoUser[0].password).use { CordaRPCClient(nodeB.rpcAddress).start(demoUser[0].username, demoUser[0].password).use {
recipient(it.proxy, nodeB.webAddress.port) recipient(it.proxy, webserverHandle.listenAddress.port)
} }
} }

View File

@ -1,5 +1,6 @@
package net.corda.bank package net.corda.bank
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.node.services.Vault import net.corda.core.node.services.Vault
@ -37,11 +38,11 @@ class BankOfCordaRPCClientTest {
).map { it.getOrThrow() } ).map { it.getOrThrow() }
// Bank of Corda RPC Client // Bank of Corda RPC Client
val bocClient = nodeBankOfCorda.rpcClientToNode() val bocClient = CordaRPCClient(nodeBankOfCorda.rpcAddress)
val bocProxy = bocClient.start("bocManager", "password1").proxy val bocProxy = bocClient.start("bocManager", "password1").proxy
// Big Corporation RPC Client // Big Corporation RPC Client
val bigCorpClient = nodeBigCorporation.rpcClientToNode() val bigCorpClient = CordaRPCClient(nodeBigCorporation.rpcAddress)
val bigCorpProxy = bigCorpClient.start("bigCorpCFO", "password2").proxy val bigCorpProxy = bigCorpClient.start("bigCorpCFO", "password2").proxy
// Register for Bank of Corda Vault updates // Register for Bank of Corda Vault updates

View File

@ -15,6 +15,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.messaging.vaultTrackBy import net.corda.core.messaging.vaultTrackBy
import net.corda.core.toFuture import net.corda.core.toFuture
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
@ -78,7 +79,7 @@ class IRSDemoTest {
registerIRSModule(mapper) registerIRSModule(mapper)
HttpApi.fromHostAndPort(it.second, "api/irs", mapper = mapper) HttpApi.fromHostAndPort(it.second, "api/irs", mapper = mapper)
} }
val nextFixingDates = getFixingDateObservable(nodeA.configuration) val nextFixingDates = getFixingDateObservable(nodeA.rpcAddress)
val numADeals = getTradeCount(nodeAApi) val numADeals = getTradeCount(nodeAApi)
val numBDeals = getTradeCount(nodeBApi) val numBDeals = getTradeCount(nodeBApi)
@ -102,8 +103,8 @@ class IRSDemoTest {
return getTrades(nodeApi)[0].calculation.floatingLegPaymentSchedule.count { it.value.rate.ratioUnit != null } return getTrades(nodeApi)[0].calculation.floatingLegPaymentSchedule.count { it.value.rate.ratioUnit != null }
} }
private fun getFixingDateObservable(config: NodeConfiguration): Observable<LocalDate?> { private fun getFixingDateObservable(address: NetworkHostAndPort): Observable<LocalDate?> {
val client = CordaRPCClient(config.rpcOptions.address!!) val client = CordaRPCClient(address)
val proxy = client.start("user", "password").proxy val proxy = client.start("user", "password").proxy
val vaultUpdates = proxy.vaultTrackBy<InterestRateSwap.State>().updates val vaultUpdates = proxy.vaultTrackBy<InterestRateSwap.State>().updates

View File

@ -7,6 +7,7 @@ import net.corda.testing.driver.DriverParameters
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.PortAllocation import net.corda.testing.driver.PortAllocation
import net.corda.testing.driver.WebserverHandle import net.corda.testing.driver.WebserverHandle
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import net.corda.testing.node.internal.* import net.corda.testing.node.internal.*
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -68,12 +69,12 @@ data class SpringBootDriverDSL(private val driverDSL: DriverDSLImpl) : InternalD
val debugPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null val debugPort = if (driverDSL.isDebug) driverDSL.debugPortAllocation.nextPort() else null
val process = startApplication(handle, debugPort, clazz) val process = startApplication(handle, debugPort, clazz)
driverDSL.shutdownManager.registerProcessShutdown(process) driverDSL.shutdownManager.registerProcessShutdown(process)
val webReadyFuture = addressMustBeBoundFuture(driverDSL.executorService, handle.webAddress, process) val webReadyFuture = addressMustBeBoundFuture(driverDSL.executorService, (handle as NodeHandleInternal).webAddress, process)
return webReadyFuture.map { queryWebserver(handle, process, checkUrl) } return webReadyFuture.map { queryWebserver(handle, process, checkUrl) }
} }
private fun queryWebserver(handle: NodeHandle, process: Process, checkUrl: String): WebserverHandle { private fun queryWebserver(handle: NodeHandle, process: Process, checkUrl: String): WebserverHandle {
val protocol = if (handle.useHTTPS) "https://" else "http://" val protocol = if ((handle as NodeHandleInternal).useHTTPS) "https://" else "http://"
val url = URL(URL("$protocol${handle.webAddress}"), checkUrl) val url = URL(URL("$protocol${handle.webAddress}"), checkUrl)
val client = OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).build() val client = OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).build()
@ -102,19 +103,19 @@ data class SpringBootDriverDSL(private val driverDSL: DriverDSLImpl) : InternalD
className = className, // cannot directly get class for this, so just use string className = className, // cannot directly get class for this, so just use string
jdwpPort = debugPort, jdwpPort = debugPort,
extraJvmArguments = listOf( extraJvmArguments = listOf(
"-Dname=node-${handle.configuration.p2pAddress}-webserver", "-Dname=node-${handle.p2pAddress}-webserver",
"-Djava.io.tmpdir=${System.getProperty("java.io.tmpdir")}" "-Djava.io.tmpdir=${System.getProperty("java.io.tmpdir")}"
// Inherit from parent process // Inherit from parent process
), ),
classpath = ProcessUtilities.defaultClassPath, classpath = ProcessUtilities.defaultClassPath,
workingDirectory = handle.configuration.baseDirectory, workingDirectory = handle.baseDirectory,
errorLogPath = Paths.get("error.$className.log"), errorLogPath = Paths.get("error.$className.log"),
arguments = listOf( arguments = listOf(
"--base-directory", handle.configuration.baseDirectory.toString(), "--base-directory", handle.baseDirectory.toString(),
"--server.port=${handle.webAddress.port}", "--server.port=${(handle as NodeHandleInternal).webAddress.port}",
"--corda.host=${handle.configuration.rpcOptions.address}", "--corda.host=${handle.rpcAddress}",
"--corda.user=${handle.configuration.rpcUsers.first().username}", "--corda.user=${handle.rpcUsers.first().username}",
"--corda.password=${handle.configuration.rpcUsers.first().password}" "--corda.password=${handle.rpcUsers.first().password}"
), ),
maximumHeapSize = null maximumHeapSize = null
) )

View File

@ -19,6 +19,7 @@ import net.corda.node.services.statemachine.*
import net.corda.testing.core.chooseIdentity import net.corda.testing.core.chooseIdentity
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetwork import net.corda.testing.node.MockNetwork
import net.corda.testing.node.internal.InternalMockNetwork
import rx.Scheduler import rx.Scheduler
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@ -105,8 +106,8 @@ class NetworkMapVisualiser : Application() {
} }
// Fire the message bullets between nodes. // Fire the message bullets between nodes.
simulation.mockNet.messagingNetwork.sentMessages.observeOn(uiThread).subscribe { msg: InMemoryMessagingNetwork.MessageTransfer -> simulation.mockNet.messagingNetwork.sentMessages.observeOn(uiThread).subscribe { msg: InMemoryMessagingNetwork.MessageTransfer ->
val senderNode: MockNetwork.MockNode = simulation.mockNet.addressToNode(msg.sender) val senderNode: InternalMockNetwork.MockNode = simulation.mockNet.addressToNode(msg.sender)
val destNode: MockNetwork.MockNode = simulation.mockNet.addressToNode(msg.recipients) val destNode: InternalMockNetwork.MockNode = simulation.mockNet.addressToNode(msg.recipients)
if (transferIsInteresting(msg)) { if (transferIsInteresting(msg)) {
viewModel.nodesToWidgets[senderNode]!!.pulseAnim.play() viewModel.nodesToWidgets[senderNode]!!.pulseAnim.play()
@ -114,7 +115,7 @@ class NetworkMapVisualiser : Application() {
} }
} }
// Pulse all parties in a trade when the trade completes // Pulse all parties in a trade when the trade completes
simulation.doneSteps.observeOn(uiThread).subscribe { nodes: Collection<MockNetwork.MockNode> -> simulation.doneSteps.observeOn(uiThread).subscribe { nodes: Collection<InternalMockNetwork.MockNode> ->
nodes.forEach { viewModel.nodesToWidgets[it]!!.longPulseAnim.play() } nodes.forEach { viewModel.nodesToWidgets[it]!!.longPulseAnim.play() }
} }

View File

@ -13,7 +13,7 @@ import net.corda.finance.utils.ScreenCoordinate
import net.corda.netmap.simulation.IRSSimulation import net.corda.netmap.simulation.IRSSimulation
import net.corda.netmap.simulation.place import net.corda.netmap.simulation.place
import net.corda.testing.core.chooseIdentity import net.corda.testing.core.chooseIdentity
import net.corda.testing.node.MockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import java.util.* import java.util.*
class VisualiserViewModel { class VisualiserViewModel {
@ -25,10 +25,10 @@ class VisualiserViewModel {
} }
} }
inner class NodeWidget(val node: MockNetwork.MockNode, val innerDot: Circle, val outerDot: Circle, val longPulseDot: Circle, inner class NodeWidget(val node: InternalMockNetwork.MockNode, val innerDot: Circle, val outerDot: Circle, val longPulseDot: Circle,
val pulseAnim: Animation, val longPulseAnim: Animation, val pulseAnim: Animation, val longPulseAnim: Animation,
val nameLabel: Label, val statusLabel: Label) { val nameLabel: Label, val statusLabel: Label) {
fun position(nodeCoords: (node: MockNetwork.MockNode) -> ScreenCoordinate) { fun position(nodeCoords: (node: InternalMockNetwork.MockNode) -> ScreenCoordinate) {
val (x, y) = nodeCoords(node) val (x, y) = nodeCoords(node)
innerDot.centerX = x innerDot.centerX = x
innerDot.centerY = y innerDot.centerY = y
@ -47,7 +47,7 @@ class VisualiserViewModel {
val trackerBoxes = HashMap<ProgressTracker, TrackerWidget>() val trackerBoxes = HashMap<ProgressTracker, TrackerWidget>()
val doneTrackers = ArrayList<ProgressTracker>() val doneTrackers = ArrayList<ProgressTracker>()
val nodesToWidgets = HashMap<MockNetwork.MockNode, NodeWidget>() val nodesToWidgets = HashMap<InternalMockNetwork.MockNode, NodeWidget>()
var bankCount: Int = 0 var bankCount: Int = 0
var serviceCount: Int = 0 var serviceCount: Int = 0
@ -78,7 +78,7 @@ class VisualiserViewModel {
} }
} }
fun nodeMapCoords(node: MockNetwork.MockNode): ScreenCoordinate { fun nodeMapCoords(node: InternalMockNetwork.MockNode): ScreenCoordinate {
// For an image of the whole world, we use: // For an image of the whole world, we use:
// return node.place.coordinate.project(mapImage.fitWidth, mapImage.fitHeight, 85.0511, -85.0511, -180.0, 180.0) // return node.place.coordinate.project(mapImage.fitWidth, mapImage.fitHeight, 85.0511, -85.0511, -180.0, 180.0)
@ -128,7 +128,7 @@ class VisualiserViewModel {
} }
} }
fun makeNodeWidget(forNode: MockNetwork.MockNode, type: String, label: CordaX500Name = CordaX500Name(organisation = "Bank of Bologna", locality = "Bologna", country = "IT"), fun makeNodeWidget(forNode: InternalMockNetwork.MockNode, type: String, label: CordaX500Name = CordaX500Name(organisation = "Bank of Bologna", locality = "Bologna", country = "IT"),
nodeType: NetworkMapVisualiser.NodeType, index: Int): NodeWidget { nodeType: NetworkMapVisualiser.NodeType, index: Int): NodeWidget {
fun emitRadarPulse(initialRadius: Double, targetRadius: Double, duration: Double): Pair<Circle, Animation> { fun emitRadarPulse(initialRadius: Double, targetRadius: Double, duration: Double): Pair<Circle, Animation> {
val pulse = Circle(initialRadius).apply { val pulse = Circle(initialRadius).apply {
@ -180,7 +180,7 @@ class VisualiserViewModel {
return widget return widget
} }
fun fireBulletBetweenNodes(senderNode: MockNetwork.MockNode, destNode: MockNetwork.MockNode, startType: String, endType: String) { fun fireBulletBetweenNodes(senderNode: InternalMockNetwork.MockNode, destNode: InternalMockNetwork.MockNode, startType: String, endType: String) {
val sx = nodesToWidgets[senderNode]!!.innerDot.centerX val sx = nodesToWidgets[senderNode]!!.innerDot.centerX
val sy = nodesToWidgets[senderNode]!!.innerDot.centerY val sy = nodesToWidgets[senderNode]!!.innerDot.centerY
val dx = nodesToWidgets[destNode]!!.innerDot.centerX val dx = nodesToWidgets[destNode]!!.innerDot.centerX

View File

@ -10,9 +10,12 @@ import net.corda.irs.api.NodeInterestRates
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.testing.core.TestIdentity import net.corda.testing.core.TestIdentity
import net.corda.testing.node.* import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetwork.MockNode import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.TestClock
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.MockNodeArgs
import rx.Observable import rx.Observable
import rx.subjects.PublishSubject import rx.subjects.PublishSubject
import java.math.BigInteger import java.math.BigInteger
@ -24,7 +27,7 @@ import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletableFuture.allOf import java.util.concurrent.CompletableFuture.allOf
import java.util.concurrent.Future import java.util.concurrent.Future
internal val MockNode.place get() = configuration.myLegalName.locality.let { CityDatabase[it] }!! internal val InternalMockNetwork.MockNode.place get() = configuration.myLegalName.locality.let { CityDatabase[it] }!!
/** /**
* Base class for network simulations that are based on the unit test / mock environment. * Base class for network simulations that are based on the unit test / mock environment.
@ -50,7 +53,7 @@ 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"))
class RatesOracleNode(args: MockNodeArgs) : MockNode(args) { class RatesOracleNode(args: MockNodeArgs) : InternalMockNetwork.MockNode(args) {
companion object { companion object {
// 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")
@ -67,7 +70,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
} }
} }
val mockNet = MockNetwork( val mockNet = InternalMockNetwork(
networkSendManuallyPumped = networkSendManuallyPumped, networkSendManuallyPumped = networkSendManuallyPumped,
threadPerNode = runAsync, threadPerNode = runAsync,
cordappPackages = listOf("net.corda.finance.contract", "net.corda.irs")) cordappPackages = listOf("net.corda.finance.contract", "net.corda.irs"))
@ -77,8 +80,8 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
val regulators = listOf(mockNet.createUnstartedNode(defaultParams.copy(legalName = DUMMY_REGULATOR.name))) val regulators = listOf(mockNet.createUnstartedNode(defaultParams.copy(legalName = DUMMY_REGULATOR.name)))
val ratesOracle = mockNet.createUnstartedNode(defaultParams.copy(legalName = RatesOracleNode.RATES_SERVICE_NAME), ::RatesOracleNode) val ratesOracle = mockNet.createUnstartedNode(defaultParams.copy(legalName = RatesOracleNode.RATES_SERVICE_NAME), ::RatesOracleNode)
// 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<MockNode> = listOf(mockNet.defaultNotaryNode.internals, ratesOracle) val serviceProviders: List<InternalMockNetwork.MockNode> = listOf(mockNet.defaultNotaryNode.internals, ratesOracle)
val banks: List<MockNode> = bankLocations.mapIndexed { i, (city, country) -> val banks: List<InternalMockNetwork.MockNode> = bankLocations.mapIndexed { i, (city, country) ->
val legalName = CordaX500Name(organisation = "Bank ${'A' + i}", locality = city, country = 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. // 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()))) mockNet.createUnstartedNode(defaultParams.copy(legalName = legalName, entropyRoot = BigInteger.valueOf(i.toLong())))
@ -86,12 +89,12 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
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.
private val _allFlowSteps = PublishSubject.create<Pair<MockNode, ProgressTracker.Change>>() private val _allFlowSteps = PublishSubject.create<Pair<InternalMockNetwork.MockNode, ProgressTracker.Change>>()
private val _doneSteps = PublishSubject.create<Collection<MockNode>>() private val _doneSteps = PublishSubject.create<Collection<InternalMockNetwork.MockNode>>()
@Suppress("unused") @Suppress("unused")
val allFlowSteps: Observable<Pair<MockNode, ProgressTracker.Change>> = _allFlowSteps val allFlowSteps: Observable<Pair<InternalMockNetwork.MockNode, ProgressTracker.Change>> = _allFlowSteps
@Suppress("unused") @Suppress("unused")
val doneSteps: Observable<Collection<MockNode>> = _doneSteps val doneSteps: Observable<Collection<InternalMockNetwork.MockNode>> = _doneSteps
private var pumpCursor = 0 private var pumpCursor = 0
@ -120,7 +123,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
* A place for simulations to stash human meaningful text about what the node is "thinking", which might appear * A place for simulations to stash human meaningful text about what the node is "thinking", which might appear
* in the UI somewhere. * in the UI somewhere.
*/ */
val extraNodeLabels: MutableMap<MockNode, String> = Collections.synchronizedMap(HashMap()) val extraNodeLabels: MutableMap<InternalMockNetwork.MockNode, String> = Collections.synchronizedMap(HashMap())
/** /**
* Iterates the simulation by one step. * Iterates the simulation by one step.
@ -151,7 +154,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
return null return null
} }
protected fun showProgressFor(nodes: List<StartedNode<MockNode>>) { protected fun showProgressFor(nodes: List<StartedNode<InternalMockNetwork.MockNode>>) {
nodes.forEach { node -> nodes.forEach { node ->
node.smm.changes.filter { it is StateMachineManager.Change.Add }.subscribe { node.smm.changes.filter { it is StateMachineManager.Change.Add }.subscribe {
linkFlowProgress(node.internals, it.logic) linkFlowProgress(node.internals, it.logic)
@ -159,7 +162,7 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
} }
} }
private fun linkFlowProgress(node: MockNode, flow: FlowLogic<*>) { private fun linkFlowProgress(node: InternalMockNetwork.MockNode, flow: FlowLogic<*>) {
val pt = flow.progressTracker ?: return val pt = flow.progressTracker ?: return
pt.changes.subscribe { change: ProgressTracker.Change -> pt.changes.subscribe { change: ProgressTracker.Change ->
// Runs on node thread. // Runs on node thread.
@ -168,14 +171,14 @@ abstract class Simulation(val networkSendManuallyPumped: Boolean,
} }
protected fun showConsensusFor(nodes: List<MockNode>) { protected fun showConsensusFor(nodes: List<InternalMockNetwork.MockNode>) {
val node = nodes.first() val node = nodes.first()
node.started!!.smm.changes.filter { it is StateMachineManager.Change.Add }.first().subscribe { node.started!!.smm.changes.filter { it is StateMachineManager.Change.Add }.first().subscribe {
linkConsensus(nodes, it.logic) linkConsensus(nodes, it.logic)
} }
} }
private fun linkConsensus(nodes: Collection<MockNode>, flow: FlowLogic<*>) { private fun linkConsensus(nodes: Collection<InternalMockNetwork.MockNode>, flow: FlowLogic<*>) {
flow.progressTracker?.changes?.subscribe { _: ProgressTracker.Change -> flow.progressTracker?.changes?.subscribe { _: ProgressTracker.Change ->
// Runs on node thread. // Runs on node thread.
if (flow.progressTracker!!.currentStep == ProgressTracker.DONE) { if (flow.progressTracker!!.currentStep == ProgressTracker.DONE) {

View File

@ -12,7 +12,7 @@ import net.corda.testing.core.BOC_NAME
import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.core.DUMMY_BANK_B_NAME import net.corda.testing.core.DUMMY_BANK_B_NAME
import net.corda.testing.core.chooseIdentity import net.corda.testing.core.chooseIdentity
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.InProcess
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.node.User import net.corda.testing.node.User
import net.corda.testing.node.internal.poll import net.corda.testing.node.internal.poll
@ -37,14 +37,14 @@ class TraderDemoTest {
startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser)), startNode(providedName = DUMMY_BANK_A_NAME, rpcUsers = listOf(demoUser)),
startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser)), startNode(providedName = DUMMY_BANK_B_NAME, rpcUsers = listOf(demoUser)),
startNode(providedName = BOC_NAME, rpcUsers = listOf(bankUser)) startNode(providedName = BOC_NAME, rpcUsers = listOf(bankUser))
).map { (it.getOrThrow() as NodeHandle.InProcess).node } ).map { (it.getOrThrow() as InProcess) }
nodeA.registerInitiatedFlow(BuyerFlow::class.java) nodeA.registerInitiatedFlow(BuyerFlow::class.java)
val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map { val (nodeARpc, nodeBRpc) = listOf(nodeA, nodeB).map {
val client = CordaRPCClient(it.internals.configuration.rpcOptions.address!!) val client = CordaRPCClient(it.rpcAddress)
client.start(demoUser.username, demoUser.password).proxy client.start(demoUser.username, demoUser.password).proxy
} }
val nodeBankRpc = let { val nodeBankRpc = let {
val client = CordaRPCClient(bankNode.internals.configuration.rpcOptions.address!!) val client = CordaRPCClient(bankNode.rpcAddress)
client.start(bankUser.username, bankUser.password).proxy client.start(bankUser.username, bankUser.password).proxy
} }
@ -56,8 +56,8 @@ class TraderDemoTest {
val expectedBCash = clientB.cashCount + 1 val expectedBCash = clientB.cashCount + 1
val expectedPaper = listOf(clientA.commercialPaperCount + 1, clientB.commercialPaperCount) val expectedPaper = listOf(clientA.commercialPaperCount + 1, clientB.commercialPaperCount)
clientBank.runIssuer(amount = 100.DOLLARS, buyerName = nodeA.info.chooseIdentity().name, sellerName = nodeB.info.chooseIdentity().name) clientBank.runIssuer(amount = 100.DOLLARS, buyerName = nodeA.services.myInfo.chooseIdentity().name, sellerName = nodeB.services.myInfo.chooseIdentity().name)
clientB.runSeller(buyerName = nodeA.info.chooseIdentity().name, amount = 5.DOLLARS) clientB.runSeller(buyerName = nodeA.services.myInfo.chooseIdentity().name, amount = 5.DOLLARS)
assertThat(clientA.cashCount).isGreaterThan(originalACash) assertThat(clientA.cashCount).isGreaterThan(originalACash)
assertThat(clientB.cashCount).isEqualTo(expectedBCash) assertThat(clientB.cashCount).isEqualTo(expectedBCash)

View File

@ -15,6 +15,7 @@ import net.corda.testing.node.internal.addressMustNotBeBound
import net.corda.testing.node.internal.internalDriver import net.corda.testing.node.internal.internalDriver
import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.http.HttpApi import net.corda.testing.http.HttpApi
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@ -27,10 +28,11 @@ class DriverTests {
private companion object { private companion object {
val DUMMY_REGULATOR_NAME = CordaX500Name("Regulator A", "Paris", "FR") val DUMMY_REGULATOR_NAME = CordaX500Name("Regulator A", "Paris", "FR")
val executorService: ScheduledExecutorService = Executors.newScheduledThreadPool(2) val executorService: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
fun nodeMustBeUp(handleFuture: CordaFuture<out NodeHandle>) = handleFuture.getOrThrow().apply { fun nodeMustBeUp(handleFuture: CordaFuture<out NodeHandle>) = handleFuture.getOrThrow().apply {
val hostAndPort = nodeInfo.addresses.single() val hostAndPort = nodeInfo.addresses.single()
// Check that the port is bound // Check that the port is bound
addressMustBeBound(executorService, hostAndPort, (this as? NodeHandle.OutOfProcess)?.process) addressMustBeBound(executorService, hostAndPort, (this as? OutOfProcess)?.process)
} }
fun nodeMustBeDown(handle: NodeHandle) { fun nodeMustBeDown(handle: NodeHandle) {
@ -80,7 +82,7 @@ class DriverTests {
val logConfigFile = projectRootDir / "config" / "dev" / "log4j2.xml" val logConfigFile = projectRootDir / "config" / "dev" / "log4j2.xml"
assertThat(logConfigFile).isRegularFile() assertThat(logConfigFile).isRegularFile()
driver(isDebug = true, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString())) { driver(isDebug = true, systemProperties = mapOf("log4j.configurationFile" to logConfigFile.toString())) {
val baseDirectory = startNode(providedName = DUMMY_BANK_A_NAME).getOrThrow().configuration.baseDirectory val baseDirectory = startNode(providedName = DUMMY_BANK_A_NAME).getOrThrow().baseDirectory
val logFile = (baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME).list { it.sorted().findFirst().get() } val logFile = (baseDirectory / NodeStartup.LOGS_DIRECTORY_NAME).list { it.sorted().findFirst().get() }
val debugLinesPresent = logFile.readLines { lines -> lines.anyMatch { line -> line.startsWith("[DEBUG]") } } val debugLinesPresent = logFile.readLines { lines -> lines.anyMatch { line -> line.startsWith("[DEBUG]") } }
assertThat(debugLinesPresent).isTrue() assertThat(debugLinesPresent).isTrue()
@ -105,7 +107,7 @@ class DriverTests {
// First check that the process-id file is created by the node on startup, so that we can be sure our check that // First check that the process-id file is created by the node on startup, so that we can be sure our check that
// it's deleted on shutdown isn't a false-positive. // it's deleted on shutdown isn't a false-positive.
driver { driver {
val baseDirectory = defaultNotaryNode.getOrThrow().configuration.baseDirectory val baseDirectory = defaultNotaryNode.getOrThrow().baseDirectory
assertThat(baseDirectory / "process-id").exists() assertThat(baseDirectory / "process-id").exists()
} }

View File

@ -2,6 +2,7 @@ package net.corda.testing.node
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import net.corda.client.jackson.JacksonSupport import net.corda.client.jackson.JacksonSupport
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.flows.* import net.corda.core.flows.*
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.core.internal.list import net.corda.core.internal.list
@ -228,7 +229,7 @@ class FlowStackSnapshotTest {
fun `flowStackSnapshot contains full frames when methods with side effects are called`() { fun `flowStackSnapshot contains full frames when methods with side effects are called`() {
driver(startNodesInProcess = true) { driver(startNodesInProcess = true) {
val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<SideEffectFlow>())))).get() val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<SideEffectFlow>())))).get()
a.rpcClientToNode().use(Constants.USER, Constants.PASSWORD) { connection -> CordaRPCClient(a.rpcAddress).use(Constants.USER, Constants.PASSWORD) { connection ->
val stackSnapshotFrames = connection.proxy.startFlow(::SideEffectFlow).returnValue.get() val stackSnapshotFrames = connection.proxy.startFlow(::SideEffectFlow).returnValue.get()
val iterator = stackSnapshotFrames.listIterator() val iterator = stackSnapshotFrames.listIterator()
assertFrame("run", false, iterator.next()) assertFrame("run", false, iterator.next())
@ -243,7 +244,7 @@ class FlowStackSnapshotTest {
fun `flowStackSnapshot contains empty frames when methods with no side effects are called`() { fun `flowStackSnapshot contains empty frames when methods with no side effects are called`() {
driver(startNodesInProcess = true) { driver(startNodesInProcess = true) {
val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<NoSideEffectFlow>())))).get() val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<NoSideEffectFlow>())))).get()
a.rpcClientToNode().use(Constants.USER, Constants.PASSWORD) { connection -> CordaRPCClient(a.rpcAddress).use(Constants.USER, Constants.PASSWORD) { connection ->
val stackSnapshotFrames = connection.proxy.startFlow(::NoSideEffectFlow).returnValue.get() val stackSnapshotFrames = connection.proxy.startFlow(::NoSideEffectFlow).returnValue.get()
val iterator = stackSnapshotFrames.listIterator() val iterator = stackSnapshotFrames.listIterator()
assertFrame("run", false, iterator.next()) assertFrame("run", false, iterator.next())
@ -258,10 +259,9 @@ class FlowStackSnapshotTest {
fun `persistFlowStackSnapshot persists empty frames to a file when methods with no side effects are called`() { fun `persistFlowStackSnapshot persists empty frames to a file when methods with no side effects are called`() {
driver(startNodesInProcess = true) { driver(startNodesInProcess = true) {
val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<PersistingNoSideEffectFlow>())))).get() val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<PersistingNoSideEffectFlow>())))).get()
CordaRPCClient(a.rpcAddress).use(Constants.USER, Constants.PASSWORD) { connection ->
a.rpcClientToNode().use(Constants.USER, Constants.PASSWORD) { connection ->
val flowId = connection.proxy.startFlow(::PersistingNoSideEffectFlow).returnValue.get() val flowId = connection.proxy.startFlow(::PersistingNoSideEffectFlow).returnValue.get()
val snapshotFromFile = readFlowStackSnapshotFromDir(a.configuration.baseDirectory, flowId) val snapshotFromFile = readFlowStackSnapshotFromDir(a.baseDirectory, flowId)
val stackSnapshotFrames = convertToStackSnapshotFrames(snapshotFromFile) val stackSnapshotFrames = convertToStackSnapshotFrames(snapshotFromFile)
val iterator = stackSnapshotFrames.listIterator() val iterator = stackSnapshotFrames.listIterator()
assertFrame("call", true, iterator.next()) assertFrame("call", true, iterator.next())
@ -276,10 +276,10 @@ class FlowStackSnapshotTest {
driver(startNodesInProcess = true) { driver(startNodesInProcess = true) {
val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<MultiplePersistingSideEffectFlow>())))).get() val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<MultiplePersistingSideEffectFlow>())))).get()
a.rpcClientToNode().use(Constants.USER, Constants.PASSWORD) { connection -> CordaRPCClient(a.rpcAddress).use(Constants.USER, Constants.PASSWORD) { connection ->
val numberOfFlowSnapshots = 5 val numberOfFlowSnapshots = 5
val flowId = connection.proxy.startFlow(::MultiplePersistingSideEffectFlow, 5).returnValue.get() val flowId = connection.proxy.startFlow(::MultiplePersistingSideEffectFlow, 5).returnValue.get()
val fileCount = countFilesInDir(a.configuration.baseDirectory, flowId) val fileCount = countFilesInDir(a.baseDirectory, flowId)
assertEquals(numberOfFlowSnapshots, fileCount) assertEquals(numberOfFlowSnapshots, fileCount)
} }
} }
@ -307,9 +307,9 @@ class FlowStackSnapshotTest {
driver(startNodesInProcess = true) { driver(startNodesInProcess = true) {
val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<PersistingSideEffectFlow>())))).get() val a = startNode(rpcUsers = listOf(User(Constants.USER, Constants.PASSWORD, setOf(startFlow<PersistingSideEffectFlow>())))).get()
a.rpcClientToNode().use(Constants.USER, Constants.PASSWORD) { connection -> CordaRPCClient(a.rpcAddress).use(Constants.USER, Constants.PASSWORD) { connection ->
val flowId = connection.proxy.startFlow(::PersistingSideEffectFlow).returnValue.get() val flowId = connection.proxy.startFlow(::PersistingSideEffectFlow).returnValue.get()
val snapshotFromFile = readFlowStackSnapshotFromDir(a.configuration.baseDirectory, flowId) val snapshotFromFile = readFlowStackSnapshotFromDir(a.baseDirectory, flowId)
var inCallCount = 0 var inCallCount = 0
var inPersistCount = 0 var inPersistCount = 0
snapshotFromFile.stackFrames.forEach { snapshotFromFile.stackFrames.forEach {

View File

@ -2,6 +2,7 @@ package net.corda.testing.node
import net.corda.core.internal.div import net.corda.core.internal.div
import net.corda.testing.common.internal.ProjectStructure.projectRootDir import net.corda.testing.common.internal.ProjectStructure.projectRootDir
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.ProcessUtilities.startJavaProcess import net.corda.testing.node.internal.ProcessUtilities.startJavaProcess
import org.junit.Test import org.junit.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals

View File

@ -0,0 +1,26 @@
package net.corda.testing.node.internal
import net.corda.core.internal.div
import net.corda.testing.common.internal.ProjectStructure.projectRootDir
import net.corda.testing.node.internal.ProcessUtilities.startJavaProcess
import org.junit.Test
import kotlin.test.assertEquals
class InternalMockNetworkIntegrationTests {
companion object {
@JvmStatic
fun main(args: Array<String>) {
InternalMockNetwork(emptyList()).run {
repeat(2) { createNode() }
runNetwork()
stopNodes()
}
}
}
@Test
fun `does not leak non-daemon threads`() {
val quasar = projectRootDir / "lib" / "quasar.jar"
assertEquals(0, startJavaProcess<InternalMockNetworkIntegrationTests>(emptyList(), extraJvmArguments = listOf("-javaagent:$quasar")).waitFor())
}
}

View File

@ -2,9 +2,9 @@
package net.corda.testing.driver package net.corda.testing.driver
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.DoNotImplement import net.corda.core.DoNotImplement
import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.CordaFuture
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
@ -12,15 +12,17 @@ import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.Node import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.VerifierType import net.corda.node.services.config.VerifierType
import net.corda.nodeapi.internal.config.SSLConfiguration import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import net.corda.testing.node.User import net.corda.testing.node.User
import net.corda.testing.node.internal.DriverDSLImpl import net.corda.testing.node.internal.DriverDSLImpl
import net.corda.testing.node.internal.genericDriver import net.corda.testing.node.internal.genericDriver
import net.corda.testing.node.internal.getTimestampAsDirectoryName import net.corda.testing.node.internal.getTimestampAsDirectoryName
import rx.Observable
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.ServerSocket import java.net.ServerSocket
import java.nio.file.Path import java.nio.file.Path
@ -33,73 +35,37 @@ import java.util.concurrent.atomic.AtomicInteger
data class NotaryHandle(val identity: Party, val validating: Boolean, val nodeHandles: CordaFuture<List<NodeHandle>>) data class NotaryHandle(val identity: Party, val validating: Boolean, val nodeHandles: CordaFuture<List<NodeHandle>>)
@DoNotImplement @DoNotImplement
sealed class NodeHandle : AutoCloseable { interface NodeHandle : AutoCloseable {
abstract val nodeInfo: NodeInfo val nodeInfo: NodeInfo
/** /**
* Interface to the node's RPC system. The first RPC user will be used to login if are any, otherwise a default one * Interface to the node's RPC system. The first RPC user will be used to login if are any, otherwise a default one
* will be added and that will be used. * will be added and that will be used.
*/ */
abstract val rpc: CordaRPCOps val rpc: CordaRPCOps
abstract val configuration: NodeConfiguration val p2pAddress: NetworkHostAndPort
abstract val webAddress: NetworkHostAndPort val rpcAddress: NetworkHostAndPort
abstract val useHTTPS: Boolean val rpcUsers: List<User>
val baseDirectory: Path
/** /**
* Stops the referenced node. * Stops the referenced node.
*/ */
abstract fun stop() fun stop()
}
@DoNotImplement
interface OutOfProcess : NodeHandle {
val process: Process
}
@DoNotImplement
interface InProcess : NodeHandle {
val database: CordaPersistence
val services: StartedNodeServices
/** /**
* Closes and stops the node. * Register a flow that is initiated by another flow
*/ */
override fun close() = stop() fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T>
data class OutOfProcess(
override val nodeInfo: NodeInfo,
override val rpc: CordaRPCOps,
override val configuration: NodeConfiguration,
override val webAddress: NetworkHostAndPort,
override val useHTTPS: Boolean,
val debugPort: Int?,
val process: Process,
private val onStopCallback: () -> Unit
) : NodeHandle() {
override fun stop() {
with(process) {
destroy()
waitFor()
}
onStopCallback()
}
}
data class InProcess(
override val nodeInfo: NodeInfo,
override val rpc: CordaRPCOps,
override val configuration: NodeConfiguration,
override val webAddress: NetworkHostAndPort,
override val useHTTPS: Boolean,
val node: StartedNode<Node>,
val nodeThread: Thread,
private val onStopCallback: () -> Unit
) : NodeHandle() {
override fun stop() {
node.dispose()
with(nodeThread) {
interrupt()
join()
}
onStopCallback()
}
}
/**
* Connects to node through RPC.
*
* @param sslConfiguration specifies SSL options.
*/
@JvmOverloads
fun rpcClientToNode(sslConfiguration: SSLConfiguration? = null): CordaRPCClient = CordaRPCClient(configuration.rpcOptions.address!!, sslConfiguration = sslConfiguration)
} }
data class WebserverHandle( data class WebserverHandle(
@ -137,12 +103,12 @@ data class NodeParameters(
val startInSameProcess: Boolean? = null, val startInSameProcess: Boolean? = null,
val maximumHeapSize: String = "200m" val maximumHeapSize: String = "200m"
) { ) {
fun setProvidedName(providedName: CordaX500Name?) = copy(providedName = providedName) fun setProvidedName(providedName: CordaX500Name?): NodeParameters = copy(providedName = providedName)
fun setRpcUsers(rpcUsers: List<User>) = copy(rpcUsers = rpcUsers) fun setRpcUsers(rpcUsers: List<User>): NodeParameters = copy(rpcUsers = rpcUsers)
fun setVerifierType(verifierType: VerifierType) = copy(verifierType = verifierType) fun setVerifierType(verifierType: VerifierType): NodeParameters = copy(verifierType = verifierType)
fun setCustomerOverrides(customOverrides: Map<String, Any?>) = copy(customOverrides = customOverrides) fun setCustomerOverrides(customOverrides: Map<String, Any?>): NodeParameters = copy(customOverrides = customOverrides)
fun setStartInSameProcess(startInSameProcess: Boolean?) = copy(startInSameProcess = startInSameProcess) fun setStartInSameProcess(startInSameProcess: Boolean?): NodeParameters = copy(startInSameProcess = startInSameProcess)
fun setMaximumHeapSize(maximumHeapSize: String) = copy(maximumHeapSize = maximumHeapSize) fun setMaximumHeapSize(maximumHeapSize: String): NodeParameters = copy(maximumHeapSize = maximumHeapSize)
} }
data class JmxPolicy(val startJmxHttpServer: Boolean = false, data class JmxPolicy(val startJmxHttpServer: Boolean = false,

View File

@ -0,0 +1,74 @@
package net.corda.testing.driver.internal
import net.corda.core.flows.FlowLogic
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.driver.InProcess
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.OutOfProcess
import net.corda.testing.node.User
import rx.Observable
import java.nio.file.Path
interface NodeHandleInternal : NodeHandle {
val configuration: NodeConfiguration
val useHTTPS: Boolean
val webAddress: NetworkHostAndPort
override val p2pAddress: NetworkHostAndPort get() = configuration.p2pAddress
override val rpcAddress: NetworkHostAndPort get() = configuration.rpcOptions.address!!
override val baseDirectory: Path get() = configuration.baseDirectory
}
data class OutOfProcessImpl(
override val nodeInfo: NodeInfo,
override val rpc: CordaRPCOps,
override val configuration: NodeConfiguration,
override val webAddress: NetworkHostAndPort,
override val useHTTPS: Boolean,
val debugPort: Int?,
override val process: Process,
private val onStopCallback: () -> Unit
) : OutOfProcess, NodeHandleInternal {
override val rpcUsers: List<User> = configuration.rpcUsers.map { User(it.username, it.password, it.permissions) }
override fun stop() {
with(process) {
destroy()
waitFor()
}
onStopCallback()
}
override fun close() = stop()
}
data class InProcessImpl(
override val nodeInfo: NodeInfo,
override val rpc: CordaRPCOps,
override val configuration: NodeConfiguration,
override val webAddress: NetworkHostAndPort,
override val useHTTPS: Boolean,
private val nodeThread: Thread,
private val onStopCallback: () -> Unit,
private val node: StartedNode<Node>
) : InProcess, NodeHandleInternal {
override val database: CordaPersistence get() = node.database
override val services: StartedNodeServices get() = node.services
override val rpcUsers: List<User> = configuration.rpcUsers.map { User(it.username, it.password, it.permissions) }
override fun stop() {
node.dispose()
with(nodeThread) {
interrupt()
join()
}
onStopCallback()
}
override fun close() = stop()
override fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T> = node.registerInitiatedFlow(initiatedFlowClass)
}

View File

@ -304,7 +304,7 @@ class InMemoryMessagingNetwork internal constructor(
override fun getAddressOfParty(partyInfo: PartyInfo): MessageRecipients { override fun getAddressOfParty(partyInfo: PartyInfo): MessageRecipients {
return when (partyInfo) { return when (partyInfo) {
is PartyInfo.SingleNode -> peersMapping[partyInfo.party.name] ?: throw IllegalArgumentException("No MockNode for party ${partyInfo.party.name}") is PartyInfo.SingleNode -> peersMapping[partyInfo.party.name] ?: throw IllegalArgumentException("No StartedMockNode for party ${partyInfo.party.name}")
is PartyInfo.DistributedNode -> ServiceHandle(partyInfo.party) is PartyInfo.DistributedNode -> ServiceHandle(partyInfo.party)
} }
} }

View File

@ -0,0 +1,178 @@
package net.corda.testing.node
import com.google.common.jimfs.Jimfs
import net.corda.core.concurrent.CordaFuture
import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo
import net.corda.node.VersionInfo
import net.corda.node.internal.StartedNode
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.messaging.MessagingService
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.setMessagingServiceSpy
import rx.Observable
import java.math.BigInteger
import java.nio.file.Path
/**
* Extend this class in order to intercept and modify messages passing through the [MessagingService] when using the [InMemoryMessagingNetwork].
*/
open class MessagingServiceSpy(val messagingService: MessagingService) : MessagingService by messagingService
/**
* @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 entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
val configOverrides: (NodeConfiguration) -> Any? = {},
val version: VersionInfo = MockServices.MOCK_VERSION_INFO) {
fun setForcedID(forcedID: Int?): MockNodeParameters = copy(forcedID = forcedID)
fun setLegalName(legalName: CordaX500Name?): MockNodeParameters = copy(legalName = legalName)
fun setEntropyRoot(entropyRoot: BigInteger): MockNodeParameters = copy(entropyRoot = entropyRoot)
fun setConfigOverrides(configOverrides: (NodeConfiguration) -> Any?): MockNodeParameters = copy(configOverrides = configOverrides)
}
/** Helper builder for configuring a [InternalMockNetwork] from Java. */
@Suppress("unused")
data class MockNetworkParameters(
val networkSendManuallyPumped: Boolean = false,
val threadPerNode: Boolean = false,
val servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random(),
val initialiseSerialization: Boolean = true,
val notarySpecs: List<MockNetworkNotarySpec> = listOf(MockNetworkNotarySpec(DUMMY_NOTARY_NAME)),
val maxTransactionSize: Int = Int.MAX_VALUE) {
fun setNetworkSendManuallyPumped(networkSendManuallyPumped: Boolean): MockNetworkParameters = copy(networkSendManuallyPumped = networkSendManuallyPumped)
fun setThreadPerNode(threadPerNode: Boolean): MockNetworkParameters = copy(threadPerNode = threadPerNode)
fun setServicePeerAllocationStrategy(servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy): MockNetworkParameters = copy(servicePeerAllocationStrategy = servicePeerAllocationStrategy)
fun setInitialiseSerialization(initialiseSerialization: Boolean): MockNetworkParameters = copy(initialiseSerialization = initialiseSerialization)
fun setNotarySpecs(notarySpecs: List<MockNetworkNotarySpec>): MockNetworkParameters = copy(notarySpecs = notarySpecs)
fun setMaxTransactionSize(maxTransactionSize: Int): MockNetworkParameters = copy(maxTransactionSize = maxTransactionSize)
}
/** Represents a node configuration for injection via [MockNetworkParameters] **/
data class MockNetworkNotarySpec(val name: CordaX500Name, val validating: Boolean = true) {
constructor(name: CordaX500Name) : this(name, validating = true)
}
/** A class that represents an unstarted mock node for testing. **/
class UnstartedMockNode private constructor(private val node: InternalMockNetwork.MockNode) {
companion object {
internal fun create(node: InternalMockNetwork.MockNode): UnstartedMockNode {
return UnstartedMockNode(node)
}
}
val id get() : Int = node.id
/** Start the node **/
fun start() = StartedMockNode.create(node.start())
}
/** A class that represents a started mock node for testing. **/
class StartedMockNode private constructor(private val node: StartedNode<InternalMockNetwork.MockNode>) {
companion object {
internal fun create(node: StartedNode<InternalMockNetwork.MockNode>): StartedMockNode {
return StartedMockNode(node)
}
}
val services get() : StartedNodeServices = node.services
val database get() : CordaPersistence = node.database
val id get() : Int = node.internals.id
val info get() : NodeInfo = node.services.myInfo
val network get() : MessagingService = node.network
/** Register a flow that is initiated by another flow **/
fun <F : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<F>): Observable<F> = node.registerInitiatedFlow(initiatedFlowClass)
/**
* Attach a [MessagingServiceSpy] to the [InternalMockNetwork.MockNode] allowing
* interception and modification of messages.
*/
fun setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) = node.setMessagingServiceSpy(messagingServiceSpy)
/** Stop the node **/
fun stop() = node.internals.stop()
/** Receive a message from the queue. */
fun pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? {
return (services.networkService as InMemoryMessagingNetwork.TestMessagingService).pumpReceive(block)
}
/** Returns the currently live flows of type [flowClass], and their corresponding result future. */
fun <F : FlowLogic<*>> findStateMachines(flowClass: Class<F>): List<Pair<F, CordaFuture<*>>> = node.smm.findStateMachines(flowClass)
}
/**
* 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
* memory H2 database instance.
*
* Mock network nodes require manual pumping by default: they will not run asynchronous. This means that
* for message exchanges to take place (and associated handlers to run), you must call the [runNetwork]
* method.
*
* You can get a printout of every message sent by using code like:
*
* LogHelper.setLevel("+messages")
*
* By default a single notary node is automatically started, which forms part of the network parameters for all the nodes.
* This node is available by calling [defaultNotaryNode].
*/
open class MockNetwork(
val cordappPackages: List<String>,
val defaultParameters: MockNetworkParameters = MockNetworkParameters(),
val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped,
val threadPerNode: Boolean = defaultParameters.threadPerNode,
val servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = defaultParameters.servicePeerAllocationStrategy,
val initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
val notarySpecs: List<MockNetworkNotarySpec> = defaultParameters.notarySpecs,
val maxTransactionSize: Int = defaultParameters.maxTransactionSize) {
@JvmOverloads
constructor(cordappPackages: List<String>, parameters: MockNetworkParameters = MockNetworkParameters()) : this(cordappPackages, defaultParameters = parameters)
private val internalMockNetwork: InternalMockNetwork = InternalMockNetwork(cordappPackages, defaultParameters, networkSendManuallyPumped, threadPerNode, servicePeerAllocationStrategy, initialiseSerialization, notarySpecs, maxTransactionSize)
val defaultNotaryNode get() : StartedMockNode = StartedMockNode.create(internalMockNetwork.defaultNotaryNode)
val defaultNotaryIdentity get() : Party = internalMockNetwork.defaultNotaryIdentity
val notaryNodes get() : List<StartedMockNode> = internalMockNetwork.notaryNodes.map { StartedMockNode.create(it) }
val nextNodeId get() : Int = internalMockNetwork.nextNodeId
/** Create a started node with the given identity. **/
fun createPartyNode(legalName: CordaX500Name? = null): StartedMockNode = StartedMockNode.create(internalMockNetwork.createPartyNode(legalName))
/** Create a started node with the given parameters. **/
fun createNode(parameters: MockNodeParameters = MockNodeParameters()): StartedMockNode = StartedMockNode.create(internalMockNetwork.createNode(parameters))
/** Create an unstarted node with the given parameters. **/
fun createUnstartedNode(parameters: MockNodeParameters = MockNodeParameters()): UnstartedMockNode = UnstartedMockNode.create(internalMockNetwork.createUnstartedNode(parameters))
/** Start all nodes that aren't already started. **/
fun startNodes() = internalMockNetwork.startNodes()
/** Stop all nodes. **/
fun stopNodes() = internalMockNetwork.stopNodes()
/** Block until all scheduled activity, active flows and network activity has ceased. **/
fun waitQuiescent() = internalMockNetwork.waitQuiescent()
/**
* Asks every node in order to process any queued up inbound messages. This may in turn result in nodes
* sending more messages to each other, thus, a typical usage is to call runNetwork with the [rounds]
* parameter set to -1 (the default) which simply runs as many rounds as necessary to result in network
* stability (no nodes sent any messages in the last round).
*/
@JvmOverloads
fun runNetwork(rounds: Int = -1) = internalMockNetwork.runNetwork(rounds)
/** Get the base directory for the given node id. **/
fun baseDirectory(nodeId: Int): Path = internalMockNetwork.baseDirectory(nodeId)
}

View File

@ -44,6 +44,9 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.DUMMY_BANK_A_NAME import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.core.setGlobalSerialization import net.corda.testing.core.setGlobalSerialization
import net.corda.testing.driver.* import net.corda.testing.driver.*
import net.corda.testing.driver.internal.InProcessImpl
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.driver.internal.OutOfProcessImpl
import net.corda.testing.node.ClusterSpec import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
@ -355,7 +358,7 @@ class DriverDSLImpl(
} }
private fun queryWebserver(handle: NodeHandle, process: Process): WebserverHandle { private fun queryWebserver(handle: NodeHandle, process: Process): WebserverHandle {
val protocol = if (handle.useHTTPS) "https://" else "http://" val protocol = if ((handle as NodeHandleInternal).useHTTPS) "https://" else "http://"
val url = URL("$protocol${handle.webAddress}/api/status") val url = URL("$protocol${handle.webAddress}/api/status")
val client = OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build() val client = OkHttpClient.Builder().connectTimeout(5, TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build()
@ -375,7 +378,7 @@ class DriverDSLImpl(
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val process = startWebserver(handle, debugPort, maximumHeapSize) val process = startWebserver(handle, debugPort, maximumHeapSize)
shutdownManager.registerProcessShutdown(process) shutdownManager.registerProcessShutdown(process)
val webReadyFuture = addressMustBeBoundFuture(executorService, handle.webAddress, process) val webReadyFuture = addressMustBeBoundFuture(executorService, (handle as NodeHandleInternal).webAddress, process)
return webReadyFuture.map { queryWebserver(handle, process) } return webReadyFuture.map { queryWebserver(handle, process) }
} }
@ -654,7 +657,7 @@ class DriverDSLImpl(
return nodeAndThreadFuture.flatMap { (node, thread) -> return nodeAndThreadFuture.flatMap { (node, thread) ->
establishRpc(config, openFuture()).flatMap { rpc -> establishRpc(config, openFuture()).flatMap { rpc ->
allNodesConnected(rpc).map { allNodesConnected(rpc).map {
NodeHandle.InProcess(rpc.nodeInfo(), rpc, config.corda, webAddress, useHTTPS, node, thread, onNodeExit) InProcessImpl(rpc.nodeInfo(), rpc, config.corda, webAddress, useHTTPS, thread, onNodeExit, node)
} }
} }
} }
@ -683,7 +686,7 @@ class DriverDSLImpl(
} }
processDeathFuture.cancel(false) processDeathFuture.cancel(false)
log.info("Node handle is ready. NodeInfo: ${rpc.nodeInfo()}, WebAddress: $webAddress") log.info("Node handle is ready. NodeInfo: ${rpc.nodeInfo()}, WebAddress: $webAddress")
NodeHandle.OutOfProcess(rpc.nodeInfo(), rpc, config.corda, webAddress, useHTTPS, debugPort, process, onNodeExit) OutOfProcessImpl(rpc.nodeInfo(), rpc, config.corda, webAddress, useHTTPS, debugPort, process, onNodeExit)
} }
} }
} }
@ -833,10 +836,10 @@ class DriverDSLImpl(
val className = "net.corda.webserver.WebServer" val className = "net.corda.webserver.WebServer"
return ProcessUtilities.startCordaProcess( return ProcessUtilities.startCordaProcess(
className = className, // cannot directly get class for this, so just use string className = className, // cannot directly get class for this, so just use string
arguments = listOf("--base-directory", handle.configuration.baseDirectory.toString()), arguments = listOf("--base-directory", handle.baseDirectory.toString()),
jdwpPort = debugPort, jdwpPort = debugPort,
extraJvmArguments = listOf( extraJvmArguments = listOf(
"-Dname=node-${handle.configuration.p2pAddress}-webserver", "-Dname=node-${handle.p2pAddress}-webserver",
"-Djava.io.tmpdir=${System.getProperty("java.io.tmpdir")}" // Inherit from parent process "-Djava.io.tmpdir=${System.getProperty("java.io.tmpdir")}" // Inherit from parent process
), ),
errorLogPath = Paths.get("error.$className.log"), errorLogPath = Paths.get("error.$className.log"),

View File

@ -1,4 +1,4 @@
package net.corda.testing.node package net.corda.testing.node.internal
import com.google.common.jimfs.Configuration.unix import com.google.common.jimfs.Configuration.unix
import com.google.common.jimfs.Jimfs import com.google.common.jimfs.Jimfs
@ -7,6 +7,7 @@ import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.DoNotImplement import net.corda.core.DoNotImplement
import net.corda.core.crypto.Crypto import net.corda.core.crypto.Crypto
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
@ -28,6 +29,7 @@ import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
import net.corda.node.internal.AbstractNode import net.corda.node.internal.AbstractNode
import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.internal.cordapp.CordappLoader import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.api.IdentityServiceInternal import net.corda.node.services.api.IdentityServiceInternal
@ -52,8 +54,11 @@ import net.corda.testing.internal.rigorousMock
import net.corda.testing.internal.testThreadFactory import net.corda.testing.internal.testThreadFactory
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.core.setGlobalSerialization
import net.corda.testing.node.*
import org.apache.activemq.artemis.utils.ReusableLatch import org.apache.activemq.artemis.utils.ReusableLatch
import org.apache.sshd.common.util.security.SecurityUtils import org.apache.sshd.common.util.security.SecurityUtils
import rx.Observable
import rx.internal.schedulers.CachedThreadScheduler import rx.internal.schedulers.CachedThreadScheduler
import java.math.BigInteger import java.math.BigInteger
import java.nio.file.Path import java.nio.file.Path
@ -63,48 +68,13 @@ import java.time.Clock
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
fun StartedNode<MockNetwork.MockNode>.pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? { fun StartedNode<InternalMockNetwork.MockNode>.pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? {
return (network as InMemoryMessagingNetwork.TestMessagingService).pumpReceive(block) return (network as InMemoryMessagingNetwork.TestMessagingService).pumpReceive(block)
} }
/** Helper builder for configuring a [MockNetwork] from Java. */
@Suppress("unused")
data class MockNetworkParameters(
val networkSendManuallyPumped: Boolean = false,
val threadPerNode: Boolean = false,
val servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random(),
val defaultFactory: (MockNodeArgs) -> MockNetwork.MockNode = MockNetwork::MockNode,
val initialiseSerialization: Boolean = true,
val notarySpecs: List<MockNetwork.NotarySpec> = listOf(MockNetwork.NotarySpec(DUMMY_NOTARY_NAME))) {
fun setNetworkSendManuallyPumped(networkSendManuallyPumped: Boolean) = copy(networkSendManuallyPumped = networkSendManuallyPumped)
fun setThreadPerNode(threadPerNode: Boolean) = copy(threadPerNode = threadPerNode)
fun setServicePeerAllocationStrategy(servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy) = copy(servicePeerAllocationStrategy = servicePeerAllocationStrategy)
fun setDefaultFactory(defaultFactory: (MockNodeArgs) -> MockNetwork.MockNode) = copy(defaultFactory = defaultFactory)
fun setInitialiseSerialization(initialiseSerialization: Boolean) = copy(initialiseSerialization = initialiseSerialization)
fun setNotarySpecs(notarySpecs: List<MockNetwork.NotarySpec>) = copy(notarySpecs = notarySpecs)
}
/**
* @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 entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
val configOverrides: (NodeConfiguration) -> Any? = {},
val version: VersionInfo = MOCK_VERSION_INFO) {
fun setForcedID(forcedID: Int?) = copy(forcedID = forcedID)
fun setLegalName(legalName: CordaX500Name?) = copy(legalName = legalName)
fun setEntropyRoot(entropyRoot: BigInteger) = copy(entropyRoot = entropyRoot)
fun setConfigOverrides(configOverrides: (NodeConfiguration) -> Any?) = copy(configOverrides = configOverrides)
}
data class MockNodeArgs( data class MockNodeArgs(
val config: NodeConfiguration, val config: NodeConfiguration,
val network: MockNetwork, val network: InternalMockNetwork,
val id: Int, val id: Int,
val entropyRoot: BigInteger, val entropyRoot: BigInteger,
val version: VersionInfo = MOCK_VERSION_INFO val version: VersionInfo = MOCK_VERSION_INFO
@ -126,19 +96,15 @@ data class MockNodeArgs(
* By default a single notary node is automatically started, which forms part of the network parameters for all the nodes. * By default a single notary node is automatically started, which forms part of the network parameters for all the nodes.
* This node is available by calling [defaultNotaryNode]. * This node is available by calling [defaultNotaryNode].
*/ */
open class MockNetwork(private val cordappPackages: List<String>, open class InternalMockNetwork(private val cordappPackages: List<String>,
defaultParameters: MockNetworkParameters = MockNetworkParameters(), defaultParameters: MockNetworkParameters = MockNetworkParameters(),
private val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped, val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped,
private val threadPerNode: Boolean = defaultParameters.threadPerNode, val threadPerNode: Boolean = defaultParameters.threadPerNode,
servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = defaultParameters.servicePeerAllocationStrategy, servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = defaultParameters.servicePeerAllocationStrategy,
private val defaultFactory: (MockNodeArgs) -> MockNode = defaultParameters.defaultFactory, initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
initialiseSerialization: Boolean = defaultParameters.initialiseSerialization, val notarySpecs: List<MockNetworkNotarySpec> = defaultParameters.notarySpecs,
private val notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs, maxTransactionSize: Int = Int.MAX_VALUE,
maxTransactionSize: Int = Int.MAX_VALUE) { val defaultFactory: (MockNodeArgs) -> MockNode = InternalMockNetwork::MockNode) {
/** Helper constructor for creating a [MockNetwork] with custom parameters from Java. */
@JvmOverloads
constructor(cordappPackages: List<String>, parameters: MockNetworkParameters = MockNetworkParameters()) : this(cordappPackages, defaultParameters = parameters)
init { init {
// Apache SSHD for whatever reason registers a SFTP FileSystemProvider - which gets loaded by JimFS. // Apache SSHD for whatever reason registers a SFTP FileSystemProvider - which gets loaded by JimFS.
// This SFTP support loads BouncyCastle, which we want to avoid. // This SFTP support loads BouncyCastle, which we want to avoid.
@ -158,7 +124,7 @@ open class MockNetwork(private val cordappPackages: List<String>,
private val serializationEnv = try { private val serializationEnv = try {
setGlobalSerialization(initialiseSerialization) setGlobalSerialization(initialiseSerialization)
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
throw IllegalStateException("Using more than one MockNetwork simultaneously is not supported.", e) throw IllegalStateException("Using more than one InternalMockNetwork simultaneously is not supported.", e)
} }
private val sharedUserCount = AtomicInteger(0) private val sharedUserCount = AtomicInteger(0)
@ -329,12 +295,12 @@ open class MockNetwork(private val cordappPackages: List<String>,
// This is not thread safe, but node construction is done on a single thread, so that should always be fine // This is not thread safe, but node construction is done on a single thread, so that should always be fine
override fun generateKeyPair(): KeyPair { override fun generateKeyPair(): KeyPair {
counter = counter.add(BigInteger.ONE) counter = counter.add(BigInteger.ONE)
// The MockNode specifically uses EdDSA keys as they are fixed and stored in json files for some tests (e.g IRSSimulation). // The StartedMockNode specifically uses EdDSA keys as they are fixed and stored in json files for some tests (e.g IRSSimulation).
return Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, counter) return Crypto.deriveKeyPairFromEntropy(Crypto.EDDSA_ED25519_SHA512, counter)
} }
/** /**
* MockNetwork will ensure nodes are connected to each other. The nodes themselves * InternalMockNetwork will ensure nodes are connected to each other. The nodes themselves
* won't be able to tell if that happened already or not. * won't be able to tell if that happened already or not.
*/ */
override fun checkNetworkMapIsInitialized() = Unit override fun checkNetworkMapIsInitialized() = Unit
@ -478,20 +444,12 @@ open class MockNetwork(private val cordappPackages: List<String>,
busyLatch.await() busyLatch.await()
} }
data class NotarySpec(val name: CordaX500Name, val validating: Boolean = true) {
constructor(name: CordaX500Name) : this(name, validating = true)
}
} }
/** /**
* Extend this class in order to intercept and modify messages passing through the [MessagingService] when using the [InMemoryMessagingNetwork]. * Attach a [MessagingServiceSpy] to the [InternalMockNetwork.MockNode] allowing interception and modification of messages.
*/ */
open class MessagingServiceSpy(val messagingService: MessagingService) : MessagingService by messagingService fun StartedNode<InternalMockNetwork.MockNode>.setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) {
/**
* Attach a [MessagingServiceSpy] to the [MockNetwork.MockNode] allowing interception and modification of messages.
*/
fun StartedNode<MockNetwork.MockNode>.setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) {
internals.setMessagingServiceSpy(messagingServiceSpy) internals.setMessagingServiceSpy(messagingServiceSpy)
} }

View File

@ -60,4 +60,4 @@ object ProcessUtilities {
} }
val defaultClassPath: String get() = System.getProperty("java.class.path") val defaultClassPath: String get() = System.getProperty("java.class.path")
} }

View File

@ -6,22 +6,15 @@ import static java.util.Collections.emptyList;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class MockNodeFactoryInJavaTest { public class MockNodeFactoryInJavaTest {
private static class CustomNode extends MockNetwork.MockNode {
private CustomNode(@NotNull MockNodeArgs args) {
super(args);
}
}
/** /**
* Does not need to run, only compile. * Does not need to run, only compile.
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static void factoryIsEasyToPassInUsingJava() { private static void factoryIsEasyToPassInUsingJava() {
//noinspection Convert2MethodRef //noinspection Convert2MethodRef
new MockNetwork(emptyList(), new MockNetworkParameters().setDefaultFactory(args -> new CustomNode(args))); new MockNetwork(emptyList());
new MockNetwork(emptyList(), new MockNetworkParameters().setDefaultFactory(CustomNode::new)); new MockNetwork(emptyList(), new MockNetworkParameters().setInitialiseSerialization(false));
//noinspection Convert2MethodRef //noinspection Convert2MethodRef
new MockNetwork(emptyList()).createNode(new MockNodeParameters(), args -> new CustomNode(args)); new MockNetwork(emptyList()).createNode(new MockNodeParameters());
new MockNetwork(emptyList()).createNode(new MockNodeParameters(), CustomNode::new);
} }
} }

View File

@ -1,18 +1,18 @@
package net.corda.testing.node package net.corda.testing.node.internal
import net.corda.core.serialization.internal.effectiveSerializationEnv import net.corda.core.serialization.internal.effectiveSerializationEnv
import org.assertj.core.api.Assertions.assertThatThrownBy import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test import org.junit.Test
class MockNetworkTests { class InternalMockNetworkTests {
@Test @Test
fun `does not leak serialization env if init fails`() { fun `does not leak serialization env if init fails`() {
val e = Exception("didn't work") val e = Exception("didn't work")
assertThatThrownBy { assertThatThrownBy {
object : MockNetwork(emptyList(), initialiseSerialization = true) { object : InternalMockNetwork(emptyList(), initialiseSerialization = true) {
override fun createNotaries() = throw e override fun createNotaries() = throw e
} }
}.isSameAs(e) }.isSameAs(e)
assertThatThrownBy { effectiveSerializationEnv }.isInstanceOf(IllegalStateException::class.java) assertThatThrownBy { effectiveSerializationEnv }.isInstanceOf(IllegalStateException::class.java)
} }
} }

View File

@ -4,6 +4,7 @@ import joptsimple.OptionSet
import net.corda.client.mock.ErrorFlowsEventGenerator import net.corda.client.mock.ErrorFlowsEventGenerator
import net.corda.client.mock.EventGenerator import net.corda.client.mock.EventGenerator
import net.corda.client.mock.Generator import net.corda.client.mock.Generator
import net.corda.client.rpc.CordaRPCClient
import net.corda.client.rpc.CordaRPCConnection import net.corda.client.rpc.CordaRPCConnection
import net.corda.core.contracts.Amount import net.corda.core.contracts.Amount
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
@ -83,7 +84,7 @@ class ExplorerSimulation(private val options: OptionSet) {
issuerNodeUSD = issuerUSD.get() issuerNodeUSD = issuerUSD.get()
arrayOf(notaryNode, aliceNode, bobNode, issuerNodeGBP, issuerNodeUSD).forEach { arrayOf(notaryNode, aliceNode, bobNode, issuerNodeGBP, issuerNodeUSD).forEach {
println("${it.nodeInfo.legalIdentities.first()} started on ${it.configuration.rpcOptions.address}") println("${it.nodeInfo.legalIdentities.first()} started on ${it.rpcAddress}")
} }
when { when {
@ -95,19 +96,19 @@ class ExplorerSimulation(private val options: OptionSet) {
private fun setUpRPC() { private fun setUpRPC() {
// Register with alice to use alice's RPC proxy to create random events. // Register with alice to use alice's RPC proxy to create random events.
val aliceClient = aliceNode.rpcClientToNode() val aliceClient = CordaRPCClient(aliceNode.rpcAddress)
val aliceConnection = aliceClient.start(user.username, user.password) val aliceConnection = aliceClient.start(user.username, user.password)
val aliceRPC = aliceConnection.proxy val aliceRPC = aliceConnection.proxy
val bobClient = bobNode.rpcClientToNode() val bobClient = CordaRPCClient(bobNode.rpcAddress)
val bobConnection = bobClient.start(user.username, user.password) val bobConnection = bobClient.start(user.username, user.password)
val bobRPC = bobConnection.proxy val bobRPC = bobConnection.proxy
val issuerClientGBP = issuerNodeGBP.rpcClientToNode() val issuerClientGBP = CordaRPCClient(issuerNodeGBP.rpcAddress)
val issuerGBPConnection = issuerClientGBP.start(manager.username, manager.password) val issuerGBPConnection = issuerClientGBP.start(manager.username, manager.password)
val issuerRPCGBP = issuerGBPConnection.proxy val issuerRPCGBP = issuerGBPConnection.proxy
val issuerClientUSD = issuerNodeUSD.rpcClientToNode() val issuerClientUSD = CordaRPCClient(issuerNodeUSD.rpcAddress)
val issuerUSDConnection = issuerClientUSD.start(manager.username, manager.password) val issuerUSDConnection = issuerClientUSD.start(manager.username, manager.password)
val issuerRPCUSD = issuerUSDConnection.proxy val issuerRPCUSD = issuerUSDConnection.proxy

View File

@ -28,6 +28,7 @@ import net.corda.testing.driver.JmxPolicy
import net.corda.testing.driver.NodeHandle import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.PortAllocation import net.corda.testing.driver.PortAllocation
import net.corda.testing.driver.driver import net.corda.testing.driver.driver
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import net.corda.testing.node.internal.* import net.corda.testing.node.internal.*
import org.apache.activemq.artemis.api.core.SimpleString import org.apache.activemq.artemis.api.core.SimpleString
@ -255,7 +256,7 @@ data class VerifierDriverDSL(private val driverDSL: DriverDSLImpl) : InternalDri
/** Starts a verifier connecting to the specified node */ /** Starts a verifier connecting to the specified node */
fun startVerifier(nodeHandle: NodeHandle): CordaFuture<VerifierHandle> { fun startVerifier(nodeHandle: NodeHandle): CordaFuture<VerifierHandle> {
return startVerifier(nodeHandle.configuration.p2pAddress) return startVerifier(nodeHandle.p2pAddress)
} }
/** Starts a verifier connecting to the specified requestor */ /** Starts a verifier connecting to the specified requestor */
@ -263,8 +264,8 @@ data class VerifierDriverDSL(private val driverDSL: DriverDSLImpl) : InternalDri
return startVerifier(verificationRequestorHandle.p2pAddress) return startVerifier(verificationRequestorHandle.p2pAddress)
} }
private fun <A> NodeHandle.connectToNode(closure: (ClientSession) -> A): A { private fun <A> NodeHandleInternal.connectToNode(closure: (ClientSession) -> A): A {
val transport = ArtemisTcpTransport.tcpTransport(ConnectionDirection.Outbound(), configuration.p2pAddress, configuration) val transport = ArtemisTcpTransport.tcpTransport(ConnectionDirection.Outbound(), p2pAddress, configuration)
val locator = ActiveMQClient.createServerLocatorWithoutHA(transport) val locator = ActiveMQClient.createServerLocatorWithoutHA(transport)
val sessionFactory = locator.createSessionFactory() val sessionFactory = locator.createSessionFactory()
val session = sessionFactory.createSession(NODE_USER, NODE_USER, false, true, true, locator.isPreAcknowledge, locator.ackBatchSize) val session = sessionFactory.createSession(NODE_USER, NODE_USER, false, true, true, locator.isPreAcknowledge, locator.ackBatchSize)
@ -277,7 +278,7 @@ data class VerifierDriverDSL(private val driverDSL: DriverDSLImpl) : InternalDri
* Waits until [number] verifiers are listening for verification requests coming from the Node. Check * Waits until [number] verifiers are listening for verification requests coming from the Node. Check
* [VerificationRequestorHandle.waitUntilNumberOfVerifiers] for an equivalent for requestors. * [VerificationRequestorHandle.waitUntilNumberOfVerifiers] for an equivalent for requestors.
*/ */
fun NodeHandle.waitUntilNumberOfVerifiers(number: Int) { fun NodeHandleInternal.waitUntilNumberOfVerifiers(number: Int) {
connectToNode { session -> connectToNode { session ->
poll(driverDSL.executorService, "$number verifiers to come online") { poll(driverDSL.executorService, "$number verifiers to come online") {
if (session.queueQuery(SimpleString(VerifierApi.VERIFICATION_REQUESTS_QUEUE_NAME)).consumerCount >= number) { if (session.queueQuery(SimpleString(VerifierApi.VERIFICATION_REQUESTS_QUEUE_NAME)).consumerCount >= number) {

View File

@ -15,6 +15,7 @@ import net.corda.node.services.config.VerifierType
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.DUMMY_NOTARY_NAME import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.core.SerializationEnvironmentRule import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.node.NotarySpec import net.corda.testing.node.NotarySpec
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -139,7 +140,7 @@ class VerifierTests {
notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, verifierType = VerifierType.OutOfProcess)) notarySpecs = listOf(NotarySpec(DUMMY_NOTARY_NAME, verifierType = VerifierType.OutOfProcess))
) { ) {
val aliceNode = startNode(providedName = ALICE_NAME).getOrThrow() val aliceNode = startNode(providedName = ALICE_NAME).getOrThrow()
val notaryNode = defaultNotaryNode.getOrThrow() val notaryNode = defaultNotaryNode.getOrThrow() as NodeHandleInternal
val alice = aliceNode.rpc.wellKnownPartyFromX500Name(ALICE_NAME)!! val alice = aliceNode.rpc.wellKnownPartyFromX500Name(ALICE_NAME)!!
startVerifier(notaryNode) startVerifier(notaryNode)
aliceNode.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), defaultNotaryIdentity).returnValue.get() aliceNode.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), defaultNotaryIdentity).returnValue.get()