Eliminate StartedNode (#3690)

* Shrink StartedNode

* Eliminate StartedNode
This commit is contained in:
Dominic Fox
2018-07-25 13:49:34 +01:00
committed by GitHub
parent 78b61d4ae4
commit f5b86d32f8
38 changed files with 174 additions and 252 deletions

View File

@ -8,8 +8,7 @@ import net.corda.finance.flows.AbstractCashFlow;
import net.corda.finance.flows.CashIssueFlow; import net.corda.finance.flows.CashIssueFlow;
import net.corda.finance.flows.CashPaymentFlow; import net.corda.finance.flows.CashPaymentFlow;
import net.corda.finance.schemas.CashSchemaV1; import net.corda.finance.schemas.CashSchemaV1;
import net.corda.node.internal.StartedNode; import net.corda.node.internal.NodeWithInfo;
import net.corda.node.internal.StartedNodeWithInternals;
import net.corda.testing.internal.InternalTestUtilsKt; import net.corda.testing.internal.InternalTestUtilsKt;
import net.corda.testing.node.User; import net.corda.testing.node.User;
import net.corda.testing.node.internal.NodeBasedTest; import net.corda.testing.node.internal.NodeBasedTest;
@ -44,7 +43,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
private Set<String> permSet = new HashSet<>(perms); private Set<String> permSet = new HashSet<>(perms);
private User rpcUser = new User("user1", "test", permSet); private User rpcUser = new User("user1", "test", permSet);
private StartedNodeWithInternals node; private NodeWithInfo node;
private CordaRPCClient client; private CordaRPCClient client;
private RPCConnection<CordaRPCOps> connection = null; private RPCConnection<CordaRPCOps> connection = null;
private CordaRPCOps rpcProxy; private CordaRPCOps rpcProxy;
@ -57,7 +56,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
node = startNode(ALICE_NAME, 1, singletonList(rpcUser)); node = startNode(ALICE_NAME, 1, singletonList(rpcUser));
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcOptions().getAddress())); client = new CordaRPCClient(requireNonNull(node.getNode().getConfiguration().getRpcOptions().getAddress()));
} }
@After @After

View File

@ -20,7 +20,7 @@ import net.corda.finance.contracts.getCashBalance
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.finance.flows.CashPaymentFlow import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.internal.StartedNodeWithInternals import net.corda.node.internal.NodeWithInfo
import net.corda.node.services.Permissions.Companion.all import net.corda.node.services.Permissions.Companion.all
import net.corda.testing.common.internal.checkNotOnClasspath import net.corda.testing.common.internal.checkNotOnClasspath
import net.corda.testing.core.* import net.corda.testing.core.*
@ -50,7 +50,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) {
val rpcUser = User("user1", "test", permissions = setOf(all())) val rpcUser = User("user1", "test", permissions = setOf(all()))
} }
private lateinit var node: StartedNodeWithInternals private lateinit var node: NodeWithInfo
private lateinit var identity: Party private lateinit var identity: Party
private lateinit var client: CordaRPCClient private lateinit var client: CordaRPCClient
private var connection: CordaRPCConnection? = null private var connection: CordaRPCConnection? = null
@ -62,7 +62,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) {
@Before @Before
fun setUp() { fun setUp() {
node = startNode(ALICE_NAME, rpcUsers = listOf(rpcUser)) node = startNode(ALICE_NAME, rpcUsers = listOf(rpcUser))
client = CordaRPCClient(node.internals.configuration.rpcOptions.address, CordaRPCClientConfiguration.DEFAULT.copy( client = CordaRPCClient(node.node.configuration.rpcOptions.address, CordaRPCClientConfiguration.DEFAULT.copy(
maxReconnectAttempts = 5 maxReconnectAttempts = 5
)) ))
identity = node.info.identityFromX500Name(ALICE_NAME) identity = node.info.identityFromX500Name(ALICE_NAME)
@ -127,7 +127,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) {
task.cancel(true) task.cancel(true)
latch.countDown() latch.countDown()
}.doOnCompleted { }.doOnCompleted {
successful = (node.internals.started == null) successful = (node.node.started == null)
task.cancel(true) task.cancel(true)
latch.countDown() latch.countDown()
}.subscribe() }.subscribe()
@ -235,7 +235,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) {
node.services.startFlow(CashIssueFlow(100.POUNDS, OpaqueBytes.of(1), identity), InvocationContext.shell()).flatMap { it.resultFuture }.getOrThrow() node.services.startFlow(CashIssueFlow(100.POUNDS, OpaqueBytes.of(1), identity), InvocationContext.shell()).flatMap { it.resultFuture }.getOrThrow()
val outOfProcessRpc = ProcessUtilities.startJavaProcess<StandaloneCashRpcClient>( val outOfProcessRpc = ProcessUtilities.startJavaProcess<StandaloneCashRpcClient>(
classPath = classPathWithoutFinance, classPath = classPathWithoutFinance,
arguments = listOf(node.internals.configuration.rpcOptions.address.toString(), financeLocation) arguments = listOf(node.node.configuration.rpcOptions.address.toString(), financeLocation)
) )
assertThat(outOfProcessRpc.waitFor()).isZero() // i.e. no exceptions were thrown assertThat(outOfProcessRpc.waitFor()).isZero() // i.e. no exceptions were thrown
} }

View File

@ -6,7 +6,7 @@ import net.corda.core.internal.packageName
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.finance.schemas.CashSchemaV1 import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.internal.StartedNodeWithInternals import net.corda.node.internal.NodeWithInfo
import net.corda.node.services.Permissions import net.corda.node.services.Permissions
import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
@ -48,13 +48,13 @@ class FlowsExecutionModeRpcTest {
class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contracts", CashSchemaV1::class.packageName)) { class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contracts", CashSchemaV1::class.packageName)) {
private val rpcUser = User("user1", "test", permissions = setOf(Permissions.all())) private val rpcUser = User("user1", "test", permissions = setOf(Permissions.all()))
private lateinit var node: StartedNodeWithInternals private lateinit var node: NodeWithInfo
private lateinit var client: CordaRPCClient private lateinit var client: CordaRPCClient
@Before @Before
fun setup() { fun setup() {
node = startNode(ALICE_NAME, rpcUsers = listOf(rpcUser)) node = startNode(ALICE_NAME, rpcUsers = listOf(rpcUser))
client = CordaRPCClient(node.internals.configuration.rpcOptions.address) client = CordaRPCClient(node.node.configuration.rpcOptions.address)
} }
@Test @Test

View File

@ -13,13 +13,13 @@ import net.corda.core.identity.Party
import net.corda.core.internal.FetchAttachmentsFlow import net.corda.core.internal.FetchAttachmentsFlow
import net.corda.core.internal.FetchDataFlow import net.corda.core.internal.FetchDataFlow
import net.corda.core.internal.hash import net.corda.core.internal.hash
import net.corda.node.internal.StartedNode
import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.testing.core.ALICE_NAME 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.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.TestStartedNode
import org.junit.AfterClass import org.junit.AfterClass
import org.junit.Test import org.junit.Test
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
@ -148,18 +148,18 @@ class AttachmentTests : WithMockNet {
//endregion //endregion
//region Operations //region Operations
private fun StartedNode.importAttachment(attachment: ByteArray) = private fun TestStartedNode.importAttachment(attachment: ByteArray) =
attachments.importAttachment(attachment.inputStream(), "test", null) attachments.importAttachment(attachment.inputStream(), "test", null)
.andRunNetwork() .andRunNetwork()
private fun StartedNode.updateAttachment(attachment: NodeAttachmentService.DBAttachment) = database.transaction { private fun TestStartedNode.updateAttachment(attachment: NodeAttachmentService.DBAttachment) = database.transaction {
session.update(attachment) session.update(attachment)
}.andRunNetwork() }.andRunNetwork()
private fun StartedNode.startAttachmentFlow(hash: SecureHash, otherSide: Party) = startFlowAndRunNetwork( private fun TestStartedNode.startAttachmentFlow(hash: SecureHash, otherSide: Party) = startFlowAndRunNetwork(
InitiatingFetchAttachmentsFlow(otherSide, setOf(hash))) InitiatingFetchAttachmentsFlow(otherSide, setOf(hash)))
private fun StartedNode.getAttachmentWithId(id: SecureHash) = private fun TestStartedNode.getAttachmentWithId(id: SecureHash) =
attachments.openAttachment(id)!! attachments.openAttachment(id)!!
//endregion //endregion

View File

@ -14,12 +14,12 @@ import net.corda.core.identity.excludeHostNode
import net.corda.core.identity.groupAbstractPartyByWellKnownParty 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.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.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.cordappsForPackages
import org.junit.AfterClass import org.junit.AfterClass
import org.junit.Test import org.junit.Test
@ -93,7 +93,7 @@ class CollectSignaturesFlowTests : WithContracts {
} }
//region Operators //region Operators
private fun StartedNode.startTestFlow(vararg party: Party) = private fun TestStartedNode.startTestFlow(vararg party: Party) =
startFlowAndRunNetwork( startFlowAndRunNetwork(
TestFlow.Initiator(DummyContract.MultiOwnerState( TestFlow.Initiator(DummyContract.MultiOwnerState(
MAGIC_NUMBER, MAGIC_NUMBER,

View File

@ -15,7 +15,6 @@ import net.corda.core.flows.mixins.WithFinality
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.transactions.ContractUpgradeLedgerTransaction import net.corda.core.transactions.ContractUpgradeLedgerTransaction
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
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.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyContractV2 import net.corda.testing.contracts.DummyContractV2
@ -84,7 +83,7 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
} }
//region RPC DSL //region RPC DSL
private fun RPCDriverDSL.startProxy(node: StartedNode, user: User): CordaRPCOps { private fun RPCDriverDSL.startProxy(node: TestStartedNode, user: User): CordaRPCOps {
return startRpcClient<CordaRPCOps>( return startRpcClient<CordaRPCOps>(
rpcAddress = startRpcServer( rpcAddress = startRpcServer(
rpcUser = user, rpcUser = user,
@ -112,16 +111,16 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
//endregion //endregion
//region Matchers //region Matchers
private fun StartedNode.hasDummyContractUpgradeTransaction() = private fun TestStartedNode.hasDummyContractUpgradeTransaction() =
hasContractUpgradeTransaction<DummyContract.State, DummyContractV2.State>() hasContractUpgradeTransaction<DummyContract.State, DummyContractV2.State>()
private inline fun <reified FROM : Any, reified TO: Any> StartedNode.hasContractUpgradeTransaction() = private inline fun <reified FROM : Any, reified TO: Any> TestStartedNode.hasContractUpgradeTransaction() =
has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>( has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>(
"a contract upgrade transaction", "a contract upgrade transaction",
{ getContractUpgradeTransaction(it) }, { getContractUpgradeTransaction(it) },
isUpgrade<FROM, TO>()) isUpgrade<FROM, TO>())
private fun StartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) = private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
services.validatedTransactions.getTransaction(state.ref.txhash)!! services.validatedTransactions.getTransaction(state.ref.txhash)!!
.resolveContractUpgradeTransaction(services) .resolveContractUpgradeTransaction(services)

View File

@ -18,13 +18,13 @@ import net.corda.finance.USD
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.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.StartedNode
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.core.ALICE_NAME 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.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.startFlow import net.corda.testing.node.internal.startFlow
import org.junit.AfterClass import org.junit.AfterClass
@ -85,14 +85,14 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
and bobNode.hasDummyContractUpgradeTransaction())) and bobNode.hasDummyContractUpgradeTransaction()))
} }
private fun StartedNode.issueCash(amount: Amount<Currency> = Amount(1000, USD)) = private fun TestStartedNode.issueCash(amount: Amount<Currency> = Amount(1000, USD)) =
services.startFlow(CashIssueFlow(amount, OpaqueBytes.of(1), notary)) services.startFlow(CashIssueFlow(amount, OpaqueBytes.of(1), notary))
.andRunNetwork() .andRunNetwork()
.resultFuture.getOrThrow() .resultFuture.getOrThrow()
private fun StartedNode.getBaseStateFromVault() = getStateFromVault(ContractState::class) private fun TestStartedNode.getBaseStateFromVault() = getStateFromVault(ContractState::class)
private fun StartedNode.getCashStateFromVault() = getStateFromVault(CashV2.State::class) private fun TestStartedNode.getCashStateFromVault() = getStateFromVault(CashV2.State::class)
private fun hasIssuedAmount(expected: Amount<Issued<Currency>>) = private fun hasIssuedAmount(expected: Amount<Issued<Currency>>) =
hasContractState(has(CashV2.State::amount, equalTo(expected))) hasContractState(has(CashV2.State::amount, equalTo(expected)))
@ -162,24 +162,24 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
} }
//region Operations //region Operations
private fun StartedNode.initiateDummyContractUpgrade(tx: SignedTransaction) = private fun TestStartedNode.initiateDummyContractUpgrade(tx: SignedTransaction) =
initiateContractUpgrade(tx, DummyContractV2::class) initiateContractUpgrade(tx, DummyContractV2::class)
private fun StartedNode.authoriseDummyContractUpgrade(tx: SignedTransaction) = private fun TestStartedNode.authoriseDummyContractUpgrade(tx: SignedTransaction) =
authoriseContractUpgrade(tx, DummyContractV2::class) authoriseContractUpgrade(tx, DummyContractV2::class)
//endregion //endregion
//region Matchers //region Matchers
private fun StartedNode.hasDummyContractUpgradeTransaction() = private fun TestStartedNode.hasDummyContractUpgradeTransaction() =
hasContractUpgradeTransaction<DummyContract.State, DummyContractV2.State>() hasContractUpgradeTransaction<DummyContract.State, DummyContractV2.State>()
private inline fun <reified FROM : Any, reified TO: Any> StartedNode.hasContractUpgradeTransaction() = private inline fun <reified FROM : Any, reified TO: Any> TestStartedNode.hasContractUpgradeTransaction() =
has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>( has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>(
"a contract upgrade transaction", "a contract upgrade transaction",
{ getContractUpgradeTransaction(it) }, { getContractUpgradeTransaction(it) },
isUpgrade<FROM, TO>()) isUpgrade<FROM, TO>())
private fun StartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) = private fun TestStartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
services.validatedTransactions.getTransaction(state.ref.txhash)!! services.validatedTransactions.getTransaction(state.ref.txhash)!!
.resolveContractUpgradeTransaction(services) .resolveContractUpgradeTransaction(services)

View File

@ -11,9 +11,9 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.finance.POUNDS import net.corda.finance.POUNDS
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.finance.issuedBy import net.corda.finance.issuedBy
import net.corda.node.internal.StartedNode
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.cordappsForPackages
import org.junit.AfterClass import org.junit.AfterClass
import org.junit.Test import org.junit.Test
@ -58,7 +58,7 @@ class FinalityFlowTests : WithFinality {
willThrow<IllegalArgumentException>()) willThrow<IllegalArgumentException>())
} }
private fun StartedNode.signCashTransactionWith(other: Party): SignedTransaction { private fun TestStartedNode.signCashTransactionWith(other: Party): SignedTransaction {
val amount = 1000.POUNDS.issuedBy(alice.ref(0)) val amount = 1000.POUNDS.issuedBy(alice.ref(0))
val builder = TransactionBuilder(notary) val builder = TransactionBuilder(notary)
Cash().generateIssue(builder, amount, other, notary) Cash().generateIssue(builder, amount, other, notary)

View File

@ -10,8 +10,8 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.node.internal.StartedNode
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.internal.TestStartedNode
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
@ -29,33 +29,33 @@ interface WithContracts : WithMockNet {
//region //region
//region Operations //region Operations
fun StartedNode.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) = fun TestStartedNode.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
services.signDummyContract(owner, magicNumber, *others).andRunNetwork() services.signDummyContract(owner, magicNumber, *others).andRunNetwork()
fun ServiceHub.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) = fun ServiceHub.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
signInitialTransaction(createDummyContract(owner, magicNumber, *others)) signInitialTransaction(createDummyContract(owner, magicNumber, *others))
fun StartedNode.collectSignatures(ptx: SignedTransaction) = fun TestStartedNode.collectSignatures(ptx: SignedTransaction) =
startFlowAndRunNetwork(CollectSignaturesFlow(ptx, emptySet())) startFlowAndRunNetwork(CollectSignaturesFlow(ptx, emptySet()))
fun StartedNode.addSignatureTo(ptx: SignedTransaction) = fun TestStartedNode.addSignatureTo(ptx: SignedTransaction) =
services.addSignature(ptx).andRunNetwork() services.addSignature(ptx).andRunNetwork()
fun <T : UpgradedContract<*, *>> fun <T : UpgradedContract<*, *>>
StartedNode.initiateContractUpgrade(tx: SignedTransaction, toClass: KClass<T>) = TestStartedNode.initiateContractUpgrade(tx: SignedTransaction, toClass: KClass<T>) =
initiateContractUpgrade(tx.tx.outRef(0), toClass) initiateContractUpgrade(tx.tx.outRef(0), toClass)
fun <S : ContractState, T : UpgradedContract<S, *>> fun <S : ContractState, T : UpgradedContract<S, *>>
StartedNode.initiateContractUpgrade(stateAndRef: StateAndRef<S>, toClass: KClass<T>) = TestStartedNode.initiateContractUpgrade(stateAndRef: StateAndRef<S>, toClass: KClass<T>) =
startFlowAndRunNetwork(ContractUpgradeFlow.Initiate(stateAndRef, toClass.java)) startFlowAndRunNetwork(ContractUpgradeFlow.Initiate(stateAndRef, toClass.java))
fun <T : UpgradedContract<*, *>> StartedNode.authoriseContractUpgrade( fun <T : UpgradedContract<*, *>> TestStartedNode.authoriseContractUpgrade(
tx: SignedTransaction, toClass: KClass<T>) = tx: SignedTransaction, toClass: KClass<T>) =
startFlow( startFlow(
ContractUpgradeFlow.Authorise(tx.tx.outRef<ContractState>(0), toClass.java) ContractUpgradeFlow.Authorise(tx.tx.outRef<ContractState>(0), toClass.java)
) )
fun StartedNode.deauthoriseContractUpgrade(tx: SignedTransaction) = startFlow( fun TestStartedNode.deauthoriseContractUpgrade(tx: SignedTransaction) = startFlow(
ContractUpgradeFlow.Deauthorise(tx.tx.outRef<ContractState>(0).ref) ContractUpgradeFlow.Deauthorise(tx.tx.outRef<ContractState>(0).ref)
) )

View File

@ -10,16 +10,16 @@ import net.corda.core.identity.Party
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.transactions.SignedTransaction import net.corda.core.transactions.SignedTransaction
import net.corda.node.internal.StartedNode
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.TestStartedNode
interface WithFinality : WithMockNet { interface WithFinality : WithMockNet {
//region Operations //region Operations
fun StartedNode.finalise(stx: SignedTransaction, vararg additionalParties: Party) = fun TestStartedNode.finalise(stx: SignedTransaction, vararg additionalParties: Party) =
startFlowAndRunNetwork(FinalityFlow(stx, additionalParties.toSet())) startFlowAndRunNetwork(FinalityFlow(stx, additionalParties.toSet()))
fun StartedNode.getValidatedTransaction(stx: SignedTransaction) = fun TestStartedNode.getValidatedTransaction(stx: SignedTransaction) =
services.validatedTransactions.getTransaction(stx.id)!! services.validatedTransactions.getTransaction(stx.id)!!
fun CordaRPCOps.finalise(stx: SignedTransaction, vararg parties: Party) = fun CordaRPCOps.finalise(stx: SignedTransaction, vararg parties: Party) =
@ -28,7 +28,7 @@ interface WithFinality : WithMockNet {
//endregion //endregion
//region Matchers //region Matchers
fun visibleTo(other: StartedNode) = object : Matcher<SignedTransaction> { fun visibleTo(other: TestStartedNode) = object : Matcher<SignedTransaction> {
override val description = "has a transaction visible to ${other.info.singleIdentity()}" override val description = "has a transaction visible to ${other.info.singleIdentity()}"
override fun invoke(actual: SignedTransaction) = override fun invoke(actual: SignedTransaction) =
equalTo(actual)(other.getValidatedTransaction(actual)) equalTo(actual)(other.getValidatedTransaction(actual))

View File

@ -9,8 +9,8 @@ import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.FlowStateMachine import net.corda.core.internal.FlowStateMachine
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.node.internal.StartedNode
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow import net.corda.testing.node.internal.startFlow
import java.util.* import java.util.*
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -41,32 +41,32 @@ interface WithMockNet {
/** /**
* Sign an initial transaction * Sign an initial transaction
*/ */
fun StartedNode.signInitialTransaction(build: TransactionBuilder.() -> TransactionBuilder) = fun TestStartedNode.signInitialTransaction(build: TransactionBuilder.() -> TransactionBuilder) =
services.signInitialTransaction(TransactionBuilder(mockNet.defaultNotaryIdentity).build()) services.signInitialTransaction(TransactionBuilder(mockNet.defaultNotaryIdentity).build())
/** /**
* Retrieve the sole instance of a state of a particular class from the node's vault * Retrieve the sole instance of a state of a particular class from the node's vault
*/ */
fun <S: ContractState> StartedNode.getStateFromVault(stateClass: KClass<S>) = fun <S: ContractState> TestStartedNode.getStateFromVault(stateClass: KClass<S>) =
services.vaultService.queryBy(stateClass.java).states.single() services.vaultService.queryBy(stateClass.java).states.single()
/** /**
* Start a flow * Start a flow
*/ */
fun <T> StartedNode.startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = services.startFlow(logic) fun <T> TestStartedNode.startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = services.startFlow(logic)
/** /**
* Start a flow and run the network immediately afterwards * Start a flow and run the network immediately afterwards
*/ */
fun <T> StartedNode.startFlowAndRunNetwork(logic: FlowLogic<T>): FlowStateMachine<T> = fun <T> TestStartedNode.startFlowAndRunNetwork(logic: FlowLogic<T>): FlowStateMachine<T> =
startFlow(logic).andRunNetwork() startFlow(logic).andRunNetwork()
fun StartedNode.createConfidentialIdentity(party: Party) = fun TestStartedNode.createConfidentialIdentity(party: Party) =
services.keyManagementService.freshKeyAndCert( services.keyManagementService.freshKeyAndCert(
services.myInfo.legalIdentitiesAndCerts.single { it.name == party.name }, services.myInfo.legalIdentitiesAndCerts.single { it.name == party.name },
false) false)
fun StartedNode.verifyAndRegister(identity: PartyAndCertificate) = fun TestStartedNode.verifyAndRegister(identity: PartyAndCertificate) =
services.identityService.verifyAndRegisterIdentity(identity) services.identityService.verifyAndRegisterIdentity(identity)
//endregion //endregion

View File

@ -13,7 +13,6 @@ import net.corda.core.internal.FetchDataFlow
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.InitiatedFlowFactory import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode
import net.corda.node.services.persistence.NodeAttachmentService import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.nodeapi.internal.persistence.currentDBSession import net.corda.nodeapi.internal.persistence.currentDBSession
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
@ -45,11 +44,11 @@ private fun
Attachment.extractContent() = ByteArrayOutputStream().apply { extractFile("content", this) }.toString(UTF_8.name()) Attachment.extractContent() = ByteArrayOutputStream().apply { extractFile("content", this) }.toString(UTF_8.name())
@Suppress("deprecation") @Suppress("deprecation")
private fun StartedNode.saveAttachment(content: String) = database.transaction { private fun TestStartedNode.saveAttachment(content: String) = database.transaction {
attachments.importAttachment(createAttachmentData(content).inputStream()) attachments.importAttachment(createAttachmentData(content).inputStream())
} }
private fun StartedNode.hackAttachment(attachmentId: SecureHash, content: String) = database.transaction { private fun TestStartedNode.hackAttachment(attachmentId: SecureHash, content: String) = database.transaction {
updateAttachment(attachmentId, createAttachmentData(content)) updateAttachment(attachmentId, createAttachmentData(content))
} }

View File

@ -10,8 +10,7 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow import net.corda.core.messaging.startFlow
import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.DataSourceFactory import net.corda.node.internal.DataSourceFactory
import net.corda.node.internal.StartedNode import net.corda.node.internal.NodeWithInfo
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions import net.corda.node.services.Permissions
import net.corda.node.services.config.PasswordEncryption import net.corda.node.services.config.PasswordEncryption
import net.corda.testing.node.internal.NodeBasedTest import net.corda.testing.node.internal.NodeBasedTest
@ -35,7 +34,7 @@ import kotlin.test.assertFailsWith
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class AuthDBTests : NodeBasedTest() { class AuthDBTests : NodeBasedTest() {
private lateinit var node: StartedNodeWithInternals private lateinit var node: NodeWithInfo
private lateinit var client: CordaRPCClient private lateinit var client: CordaRPCClient
private lateinit var db: UsersDB private lateinit var db: UsersDB
@ -95,7 +94,7 @@ class AuthDBTests : NodeBasedTest() {
) )
node = startNode(ALICE_NAME, rpcUsers = emptyList(), configOverrides = securityConfig) node = startNode(ALICE_NAME, rpcUsers = emptyList(), configOverrides = securityConfig)
client = CordaRPCClient(node.internals.configuration.rpcOptions.address) client = CordaRPCClient(node.node.configuration.rpcOptions.address)
} }
@Test @Test

View File

@ -21,7 +21,6 @@ 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.core.utilities.seconds import net.corda.core.utilities.seconds
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
@ -33,10 +32,7 @@ import net.corda.testing.contracts.DummyContract
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.TestClock import net.corda.testing.node.TestClock
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.hamcrest.Matchers.instanceOf import org.hamcrest.Matchers.instanceOf
import org.junit.AfterClass import org.junit.AfterClass
import org.junit.Assert.assertThat import org.junit.Assert.assertThat
@ -56,7 +52,7 @@ class BFTNotaryServiceTests {
companion object { companion object {
private lateinit var mockNet: InternalMockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var node: StartedNode private lateinit var node: TestStartedNode
@BeforeClass @BeforeClass
@JvmStatic @JvmStatic
@ -74,7 +70,7 @@ class BFTNotaryServiceTests {
mockNet.stopNodes() mockNet.stopNodes()
} }
fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair<Party, StartedNode> { fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair<Party, TestStartedNode> {
(Paths.get("config") / "currentView").deleteIfExists() // XXX: Make config object warn if this exists? (Paths.get("config") / "currentView").deleteIfExists() // XXX: Make config object warn if this exists?
val replicaIds = (0 until clusterSize) val replicaIds = (0 until clusterSize)
@ -214,7 +210,7 @@ class BFTNotaryServiceTests {
signatures.forEach { it.verify(txId) } signatures.forEach { it.verify(txId) }
} }
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction { private fun TestStartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction( return services.signInitialTransaction(
TransactionBuilder(notary).apply { TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey)) addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -6,7 +6,6 @@ import net.corda.core.identity.Party
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.node.services.BFTNotaryServiceTests.Companion.startBftClusterAndNode import net.corda.node.services.BFTNotaryServiceTests.Companion.startBftClusterAndNode
import net.corda.node.services.transactions.minClusterSize import net.corda.node.services.transactions.minClusterSize
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
@ -14,6 +13,7 @@ import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow import net.corda.testing.node.internal.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
@ -48,7 +48,7 @@ class BFTSMaRtTests {
f.getOrThrow() f.getOrThrow()
} }
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction { private fun TestStartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction( return services.signInitialTransaction(
TransactionBuilder(notary).apply { TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey)) addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -5,7 +5,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party import net.corda.core.identity.Party
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.StartedNode import net.corda.node.internal.NodeWithInfo
import net.corda.testing.core.* import net.corda.testing.core.*
import net.corda.testing.node.internal.NodeBasedTest import net.corda.testing.node.internal.NodeBasedTest
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
@ -108,7 +108,7 @@ class PersistentNetworkMapCacheTest : NodeBasedTest() {
// HELPERS // HELPERS
// Helper function to restart nodes with the same host and port. // Helper function to restart nodes with the same host and port.
private fun startNodesWithPort(nodesToStart: List<Party>, customRetryIntervalMs: Long? = null): List<StartedNode> { private fun startNodesWithPort(nodesToStart: List<Party>, customRetryIntervalMs: Long? = null): List<NodeWithInfo> {
return nodesToStart.map { party -> return nodesToStart.map { party ->
val configOverrides = (addressesMap[party.name]?.let { mapOf("p2pAddress" to it.toString()) } ?: emptyMap()) + val configOverrides = (addressesMap[party.name]?.let { mapOf("p2pAddress" to it.toString()) } ?: emptyMap()) +
(customRetryIntervalMs?.let { mapOf("activeMQServer.bridge.retryIntervalMs" to it.toString()) } ?: emptyMap()) (customRetryIntervalMs?.let { mapOf("activeMQServer.bridge.retryIntervalMs" to it.toString()) } ?: emptyMap())

View File

@ -20,7 +20,7 @@ class FlowVersioningTest : NodeBasedTest() {
fun `getFlowContext returns the platform version for core flows`() { fun `getFlowContext returns the platform version for core flows`() {
val alice = startNode(ALICE_NAME, platformVersion = 2) val alice = startNode(ALICE_NAME, platformVersion = 2)
val bob = startNode(BOB_NAME, platformVersion = 3) val bob = startNode(BOB_NAME, platformVersion = 3)
bob.internals.installCoreFlow(PretendInitiatingCoreFlow::class, ::PretendInitiatedCoreFlow) bob.node.installCoreFlow(PretendInitiatingCoreFlow::class, ::PretendInitiatedCoreFlow)
val (alicePlatformVersionAccordingToBob, bobPlatformVersionAccordingToAlice) = alice.services.startFlow( val (alicePlatformVersionAccordingToBob, bobPlatformVersionAccordingToAlice) = alice.services.startFlow(
PretendInitiatingCoreFlow(bob.info.singleIdentity())).resultFuture.getOrThrow() PretendInitiatingCoreFlow(bob.info.singleIdentity())).resultFuture.getOrThrow()
assertThat(alicePlatformVersionAccordingToBob).isEqualTo(2) assertThat(alicePlatformVersionAccordingToBob).isEqualTo(2)

View File

@ -30,7 +30,7 @@ import java.nio.file.Files
*/ */
class MQSecurityAsNodeTest : P2PMQSecurityTest() { class MQSecurityAsNodeTest : P2PMQSecurityTest() {
override fun createAttacker(): SimpleMQClient { override fun createAttacker(): SimpleMQClient {
return clientTo(alice.internals.configuration.p2pAddress) return clientTo(alice.node.configuration.p2pAddress)
} }
override fun startAttacker(attacker: SimpleMQClient) { override fun startAttacker(attacker: SimpleMQClient) {
@ -44,7 +44,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
@Test @Test
fun `only the node running the broker can login using the special P2P node user`() { fun `only the node running the broker can login using the special P2P node user`() {
val attacker = clientTo(alice.internals.configuration.p2pAddress) val attacker = clientTo(alice.node.configuration.p2pAddress)
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy { assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
attacker.start(NODE_P2P_USER, NODE_P2P_USER) attacker.start(NODE_P2P_USER, NODE_P2P_USER)
} }
@ -52,7 +52,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
@Test @Test
fun `login as the default cluster user`() { fun `login as the default cluster user`() {
val attacker = clientTo(alice.internals.configuration.p2pAddress) val attacker = clientTo(alice.node.configuration.p2pAddress)
assertThatExceptionOfType(ActiveMQClusterSecurityException::class.java).isThrownBy { assertThatExceptionOfType(ActiveMQClusterSecurityException::class.java).isThrownBy {
attacker.start(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword()) attacker.start(ActiveMQDefaultConfiguration.getDefaultClusterUser(), ActiveMQDefaultConfiguration.getDefaultClusterPassword())
} }
@ -60,7 +60,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
@Test @Test
fun `login without a username and password`() { fun `login without a username and password`() {
val attacker = clientTo(alice.internals.configuration.p2pAddress) val attacker = clientTo(alice.node.configuration.p2pAddress)
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy { assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
attacker.start() attacker.start()
} }
@ -68,7 +68,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
@Test @Test
fun `login to a non ssl port as a node user`() { fun `login to a non ssl port as a node user`() {
val attacker = clientTo(alice.internals.configuration.rpcOptions.address, sslConfiguration = null) val attacker = clientTo(alice.node.configuration.rpcOptions.address, sslConfiguration = null)
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy { assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
attacker.start(NODE_P2P_USER, NODE_P2P_USER, enableSSL = false) attacker.start(NODE_P2P_USER, NODE_P2P_USER, enableSSL = false)
} }
@ -76,7 +76,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
@Test @Test
fun `login to a non ssl port as a peer user`() { fun `login to a non ssl port as a peer user`() {
val attacker = clientTo(alice.internals.configuration.rpcOptions.address, sslConfiguration = null) val attacker = clientTo(alice.node.configuration.rpcOptions.address, sslConfiguration = null)
assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy { assertThatExceptionOfType(ActiveMQSecurityException::class.java).isThrownBy {
attacker.start(PEER_USER, PEER_USER, enableSSL = false) // Login as a peer attacker.start(PEER_USER, PEER_USER, enableSSL = false) // Login as a peer
} }
@ -133,7 +133,7 @@ class MQSecurityAsNodeTest : P2PMQSecurityTest() {
} }
} }
val attacker = clientTo(alice.internals.configuration.p2pAddress, sslConfig) val attacker = clientTo(alice.node.configuration.p2pAddress, sslConfig)
assertThatExceptionOfType(ActiveMQNotConnectedException::class.java).isThrownBy { assertThatExceptionOfType(ActiveMQNotConnectedException::class.java).isThrownBy {
attacker.start(PEER_USER, PEER_USER) attacker.start(PEER_USER, PEER_USER)

View File

@ -8,7 +8,7 @@ import org.junit.Test
*/ */
class MQSecurityAsRPCTest : RPCMQSecurityTest() { class MQSecurityAsRPCTest : RPCMQSecurityTest() {
override fun createAttacker(): SimpleMQClient { override fun createAttacker(): SimpleMQClient {
return clientTo(alice.internals.configuration.rpcOptions.address) return clientTo(alice.node.configuration.rpcOptions.address)
} }
@Test @Test

View File

@ -14,7 +14,7 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
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.StartedNodeWithInternals import net.corda.node.internal.NodeWithInfo
import net.corda.nodeapi.RPCApi import net.corda.nodeapi.RPCApi
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.INTERNAL_PREFIX import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.INTERNAL_PREFIX
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NOTIFICATIONS_ADDRESS import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NOTIFICATIONS_ADDRESS
@ -25,7 +25,6 @@ import net.corda.testing.node.User
import net.corda.testing.core.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.internal.configureTestSSL import net.corda.testing.internal.configureTestSSL
import net.corda.testing.node.internal.NodeBasedTest import net.corda.testing.node.internal.NodeBasedTest
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow import net.corda.testing.node.internal.startFlow
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
@ -44,7 +43,7 @@ import kotlin.test.assertEquals
*/ */
abstract class MQSecurityTest : NodeBasedTest() { abstract class MQSecurityTest : NodeBasedTest() {
val rpcUser = User("user1", "pass", permissions = emptySet()) val rpcUser = User("user1", "pass", permissions = emptySet())
lateinit var alice: StartedNodeWithInternals lateinit var alice: NodeWithInfo
lateinit var attacker: SimpleMQClient lateinit var attacker: SimpleMQClient
private val clients = ArrayList<SimpleMQClient>() private val clients = ArrayList<SimpleMQClient>()
@ -112,9 +111,9 @@ abstract class MQSecurityTest : NodeBasedTest() {
} }
fun loginToRPCAndGetClientQueue(): String { fun loginToRPCAndGetClientQueue(): String {
loginToRPC(alice.internals.configuration.rpcOptions.address, rpcUser) loginToRPC(alice.node.configuration.rpcOptions.address, rpcUser)
val clientQueueQuery = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.${rpcUser.username}.*") val clientQueueQuery = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.${rpcUser.username}.*")
val client = clientTo(alice.internals.configuration.rpcOptions.address) val client = clientTo(alice.node.configuration.rpcOptions.address)
client.start(rpcUser.username, rpcUser.password, false) client.start(rpcUser.username, rpcUser.password, false)
return client.session.addressQuery(clientQueueQuery).queueNames.single().toString() return client.session.addressQuery(clientQueueQuery).queueNames.single().toString()
} }

View File

@ -110,7 +110,7 @@ import net.corda.core.crypto.generateKeyPair as cryptoGenerateKeyPair
// In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the // In theory the NodeInfo for the node should be passed in, instead, however currently this is constructed by the
// AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in. // AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in.
abstract class AbstractNode<S : StartedNode>(val configuration: NodeConfiguration, abstract class AbstractNode<S>(val configuration: NodeConfiguration,
val platformClock: CordaClock, val platformClock: CordaClock,
protected val versionInfo: VersionInfo, protected val versionInfo: VersionInfo,
protected val cordappLoader: CordappLoader, protected val cordappLoader: CordappLoader,
@ -183,7 +183,7 @@ abstract class AbstractNode<S : StartedNode>(val configuration: NodeConfiguratio
val services = ServiceHubInternalImpl().tokenize() val services = ServiceHubInternalImpl().tokenize()
@Suppress("LeakingThis") @Suppress("LeakingThis")
val smm = makeStateMachineManager() val smm = makeStateMachineManager()
protected val flowStarter = FlowStarterImpl(smm, flowLogicRefFactory) val flowStarter = FlowStarterImpl(smm, flowLogicRefFactory)
private val schedulerService = NodeSchedulerService( private val schedulerService = NodeSchedulerService(
platformClock, platformClock,
database, database,
@ -221,7 +221,7 @@ abstract class AbstractNode<S : StartedNode>(val configuration: NodeConfiguratio
/** Set to non-null once [start] has been successfully called. */ /** Set to non-null once [start] has been successfully called. */
open val started get() = _started open val started get() = _started
@Volatile @Volatile
private var _started: StartedNode? = null private var _started: S? = null
private fun <T : Any> T.tokenize(): T { private fun <T : Any> T.tokenize(): T {
tokenizableServices?.add(this) ?: throw IllegalStateException("The tokenisable services list has already been finialised") tokenizableServices?.add(this) ?: throw IllegalStateException("The tokenisable services list has already been finialised")
@ -625,7 +625,7 @@ abstract class AbstractNode<S : StartedNode>(val configuration: NodeConfiguratio
} }
} }
protected fun <T : FlowLogic<*>> registerInitiatedFlow(smm: StateMachineManager, initiatedFlowClass: Class<T>): Observable<T> { fun <T : FlowLogic<*>> registerInitiatedFlow(smm: StateMachineManager, initiatedFlowClass: Class<T>): Observable<T> {
return registerInitiatedFlowInternal(smm, initiatedFlowClass, track = true) return registerInitiatedFlowInternal(smm, initiatedFlowClass, track = true)
} }

View File

@ -4,6 +4,7 @@ import com.codahale.metrics.JmxReporter
import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationScheme import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationScheme
import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.CordaFuture
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy
import net.corda.core.identity.CordaX500Name import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.Emoji import net.corda.core.internal.Emoji
@ -13,8 +14,6 @@ import net.corda.core.internal.div
import net.corda.core.internal.errors.AddressBindingException import net.corda.core.internal.errors.AddressBindingException
import net.corda.core.internal.notary.NotaryService import net.corda.core.internal.notary.NotaryService
import net.corda.node.services.api.StartedNodeServices import net.corda.node.services.api.StartedNodeServices
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.RPCOps import net.corda.core.messaging.RPCOps
import net.corda.core.node.NetworkParameters import net.corda.core.node.NetworkParameters
@ -67,15 +66,13 @@ import java.time.Clock
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import javax.management.ObjectName import javax.management.ObjectName
import kotlin.system.exitProcess import kotlin.system.exitProcess
import net.corda.node.services.persistence.NodeAttachmentService import rx.Observable
/**
* A version of [StartedNode] which exposes its [Node] internals. class NodeWithInfo(val node: Node, val info: NodeInfo) {
* val services: StartedNodeServices = object : StartedNodeServices, ServiceHubInternal by node.services, FlowStarter by node.flowStarter {}
* Although this is the type of [StartedNode] created by [Node], it is not explicitly provided fun dispose() = node.stop()
* and should not ordinarily be used (the code that _does_ use it obtains it via a cast). fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T> =
*/ node.registerInitiatedFlow(node.smm, initiatedFlowClass)
interface StartedNodeWithInternals : StartedNode {
val internals: Node
} }
/** /**
@ -88,7 +85,7 @@ open class Node(configuration: NodeConfiguration,
versionInfo: VersionInfo, versionInfo: VersionInfo,
private val initialiseSerialization: Boolean = true, private val initialiseSerialization: Boolean = true,
cordappLoader: CordappLoader = makeCordappLoader(configuration) cordappLoader: CordappLoader = makeCordappLoader(configuration)
) : AbstractNode<StartedNode>( ) : AbstractNode<NodeInfo>(
configuration, configuration,
createClock(configuration), createClock(configuration),
versionInfo, versionInfo,
@ -97,36 +94,8 @@ open class Node(configuration: NodeConfiguration,
AffinityExecutor.ServiceAffinityExecutor("Node thread-${sameVmNodeCounter.incrementAndGet()}", 1) AffinityExecutor.ServiceAffinityExecutor("Node thread-${sameVmNodeCounter.incrementAndGet()}", 1)
) { ) {
/** The actual [StartedNode] implementation created by this [AbstractNode]. */ override fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): NodeInfo =
private class StartedNodeWithInternalsImpl( nodeInfo
override val internals: Node,
override val attachments: NodeAttachmentService,
override val network: MessagingService,
override val services: StartedNodeServices,
override val info: NodeInfo,
override val smm: StateMachineManager,
override val database: CordaPersistence,
override val rpcOps: CordaRPCOps,
override val notaryService: NotaryService?) : StartedNodeWithInternals {
override fun dispose() = internals.stop()
override fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>) =
internals.registerInitiatedFlow(smm, initiatedFlowClass)
}
override fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): StartedNode =
StartedNodeWithInternalsImpl(
this,
attachments,
network,
object : StartedNodeServices, ServiceHubInternal by services, FlowStarter by flowStarter { },
nodeInfo,
smm,
database,
rpcOps,
notaryService
)
companion object { companion object {
private val staticLog = contextLogger() private val staticLog = contextLogger()
@ -399,15 +368,15 @@ open class Node(configuration: NodeConfiguration,
return super.generateAndSaveNodeInfo() return super.generateAndSaveNodeInfo()
} }
override fun start(): StartedNode { override fun start(): NodeInfo {
initialiseSerialization() initialiseSerialization()
val started: StartedNode = super.start() val nodeInfo: NodeInfo = super.start()
nodeReadyFuture.thenMatch({ nodeReadyFuture.thenMatch({
serverThread.execute { serverThread.execute {
// Begin exporting our own metrics via JMX. These can be monitored using any agent, e.g. Jolokia: // Begin exporting our own metrics via JMX. These can be monitored using any agent, e.g. Jolokia:
// //
// https://jolokia.org/agent/jvm.html // https://jolokia.org/agent/jvm.html
JmxReporter.forRegistry(started.services.monitoringService.metrics).inDomain("net.corda").createsObjectNamesWith { _, domain, name -> JmxReporter.forRegistry(services.monitoringService.metrics).inDomain("net.corda").createsObjectNamesWith { _, domain, name ->
// Make the JMX hierarchy a bit better organised. // Make the JMX hierarchy a bit better organised.
val category = name.substringBefore('.') val category = name.substringBefore('.')
val subName = name.substringAfter('.', "") val subName = name.substringAfter('.', "")
@ -425,7 +394,7 @@ open class Node(configuration: NodeConfiguration,
shutdownHook = addShutdownHook { shutdownHook = addShutdownHook {
stop() stop()
} }
return started return nodeInfo
} }
override val rxIoScheduler: Scheduler get() = Schedulers.io() override val rxIoScheduler: Scheduler get() = Schedulers.io()

View File

@ -324,18 +324,18 @@ open class NodeStartup(val args: Array<String>) {
} }
} }
val startedNode = node.start() val nodeInfo = node.start()
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name }) Node.printBasicNodeInfo("Loaded CorDapps", node.services.cordappProvider.cordapps.joinToString { it.name })
node.nodeReadyFuture.thenMatch({ node.nodeReadyFuture.thenMatch({
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0 val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation val name = nodeInfo.legalIdentitiesAndCerts.first().name.organisation
Node.printBasicNodeInfo("Node for \"$name\" started up and registered in $elapsed sec") Node.printBasicNodeInfo("Node for \"$name\" started up and registered in $elapsed sec")
// Don't start the shell if there's no console attached. // Don't start the shell if there's no console attached.
if (conf.shouldStartLocalShell()) { if (conf.shouldStartLocalShell()) {
node.startupComplete.then { node.startupComplete.then {
try { try {
InteractiveShell.runLocalShell({ startedNode.dispose() }) InteractiveShell.runLocalShell({ node.stop() })
} catch (e: Throwable) { } catch (e: Throwable) {
logger.error("Shell failed to start", e) logger.error("Shell failed to start", e)
} }

View File

@ -1,34 +0,0 @@
package net.corda.node.internal
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.notary.NotaryService
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NodeInfo
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.nodeapi.internal.persistence.CordaPersistence
import rx.Observable
interface StartedNode {
val services: StartedNodeServices
val info: NodeInfo
val smm: StateMachineManager
val attachments: NodeAttachmentService
val network: MessagingService
val database: CordaPersistence
val rpcOps: CordaRPCOps
val notaryService: NotaryService?
fun dispose()
/**
* Use this method to register your initiated flows in your tests. This is automatically done by the node when it
* starts up for all [FlowLogic] classes it finds which are annotated with [InitiatedBy].
* @return An [Observable] of the initiated flows started by counterparties.
*/
fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T>
}

View File

@ -27,7 +27,6 @@ import net.corda.finance.GBP
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.internal.StartedNode
import net.corda.node.internal.security.RPCSecurityManagerImpl import net.corda.node.internal.security.RPCSecurityManagerImpl
import net.corda.node.services.Permissions.Companion.invokeRpc import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow import net.corda.node.services.Permissions.Companion.startFlow
@ -42,6 +41,7 @@ import net.corda.testing.core.sequence
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.TestStartedNode
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.* import org.assertj.core.api.Assertions.*
@ -71,7 +71,7 @@ class CordaRPCOpsImplTest {
} }
private lateinit var mockNet: InternalMockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode private lateinit var aliceNode: TestStartedNode
private lateinit var alice: Party private lateinit var alice: Party
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var rpc: CordaRPCOps private lateinit var rpc: CordaRPCOps

View File

@ -34,7 +34,6 @@ import net.corda.finance.contracts.asset.CASH
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.TwoPartyTradeFlow.Buyer import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
import net.corda.finance.flows.TwoPartyTradeFlow.Seller import net.corda.finance.flows.TwoPartyTradeFlow.Seller
import net.corda.node.internal.StartedNode
import net.corda.node.services.api.IdentityServiceInternal import net.corda.node.services.api.IdentityServiceInternal
import net.corda.node.services.api.WritableTransactionStorage import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.persistence.DBTransactionStorage import net.corda.node.services.persistence.DBTransactionStorage
@ -313,7 +312,7 @@ 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(name: CordaX500Name): StartedNode { private fun makeNodeWithTracking(name: CordaX500Name): TestStartedNode {
// Create a node in the mock network ... // Create a node in the mock network ...
return mockNet.createNode(InternalMockNodeParameters(legalName = name), nodeFactory = { args, cordappLoader -> return mockNet.createNode(InternalMockNodeParameters(legalName = name), nodeFactory = { args, cordappLoader ->
if (cordappLoader != null) { if (cordappLoader != null) {
@ -543,8 +542,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun runBuyerAndSeller(notary: Party, private fun runBuyerAndSeller(notary: Party,
buyer: Party, buyer: Party,
sellerNode: StartedNode, sellerNode: TestStartedNode,
buyerNode: StartedNode, buyerNode: TestStartedNode,
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 }
@ -638,10 +637,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun insertFakeTransactions( private fun insertFakeTransactions(
wtxToSign: List<WireTransaction>, wtxToSign: List<WireTransaction>,
node: StartedNode, node: TestStartedNode,
identity: Party, identity: Party,
notaryNode: StartedNode, notaryNode: TestStartedNode,
vararg extraSigningNodes: StartedNode): Map<SecureHash, SignedTransaction> { vararg extraSigningNodes: TestStartedNode): Map<SecureHash, SignedTransaction> {
val notaryParty = mockNet.defaultNotaryIdentity val notaryParty = mockNet.defaultNotaryIdentity
val signed = wtxToSign.map { val signed = wtxToSign.map {
val id = it.id val id = it.id

View File

@ -10,16 +10,12 @@ import net.corda.core.identity.Party
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.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.internal.StartedNode
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.ALICE_NAME 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.internal.cordappsForPackages import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -34,8 +30,8 @@ import kotlin.test.fail
class ScheduledFlowsDrainingModeTest { class ScheduledFlowsDrainingModeTest {
private lateinit var mockNet: InternalMockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: StartedNode private lateinit var bobNode: TestStartedNode
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

View File

@ -10,7 +10,6 @@ import net.corda.core.utilities.getOrThrow
import net.corda.finance.POUNDS import net.corda.finance.POUNDS
import net.corda.finance.contracts.asset.Cash import net.corda.finance.contracts.asset.Cash
import net.corda.finance.issuedBy import net.corda.finance.issuedBy
import net.corda.node.internal.StartedNode
import net.corda.node.services.statemachine.StaffedFlowHospital import net.corda.node.services.statemachine.StaffedFlowHospital
import net.corda.node.services.statemachine.StaffedFlowHospital.MedicalRecord.KeptInForObservation import net.corda.node.services.statemachine.StaffedFlowHospital.MedicalRecord.KeptInForObservation
import net.corda.testing.core.ALICE_NAME import net.corda.testing.core.ALICE_NAME
@ -19,6 +18,7 @@ import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.TestCorDapp import net.corda.testing.driver.TestCorDapp
import net.corda.testing.node.internal.InternalMockNetwork import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow import net.corda.testing.node.internal.startFlow
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
@ -75,7 +75,7 @@ class FinalityHandlerTest {
assertThat(bob.getTransaction(finalisedTx.id)).isNull() assertThat(bob.getTransaction(finalisedTx.id)).isNull()
} }
private fun StartedNode.assertFlowSentForObservation(runId: StateMachineRunId) { private fun TestStartedNode.assertFlowSentForObservation(runId: StateMachineRunId) {
val keptInForObservation = smm.flowHospital val keptInForObservation = smm.flowHospital
.track() .track()
.let { it.updates.startWith(it.snapshot) } .let { it.updates.startWith(it.snapshot) }
@ -86,7 +86,7 @@ class FinalityHandlerTest {
assertThat(keptInForObservation.by).contains(StaffedFlowHospital.FinalityDoctor) assertThat(keptInForObservation.by).contains(StaffedFlowHospital.FinalityDoctor)
} }
private fun StartedNode.getTransaction(id: SecureHash): SignedTransaction? { private fun TestStartedNode.getTransaction(id: SecureHash): SignedTransaction? {
return database.transaction { return database.transaction {
services.validatedTransactions.getTransaction(id) services.validatedTransactions.getTransaction(id)
} }

View File

@ -22,7 +22,6 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.ProgressTracker import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.FlowTimeoutConfiguration import net.corda.node.services.config.FlowTimeoutConfiguration
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NotaryConfig import net.corda.node.services.config.NotaryConfig
@ -35,10 +34,7 @@ import net.corda.testing.core.singleIdentity
import net.corda.testing.internal.LogHelper import net.corda.testing.internal.LogHelper
import net.corda.testing.node.InMemoryMessagingNetwork import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.MockNetworkParameters import net.corda.testing.node.MockNetworkParameters
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.junit.AfterClass import org.junit.AfterClass
import org.junit.Before import org.junit.Before
import org.junit.BeforeClass import org.junit.BeforeClass
@ -58,7 +54,7 @@ class TimedFlowTests {
private lateinit var mockNet: InternalMockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var node: StartedNode private lateinit var node: TestStartedNode
init { init {
LogHelper.setLevel("+net.corda.flow", "+net.corda.testing.node", "+net.corda.node.services.messaging") LogHelper.setLevel("+net.corda.flow", "+net.corda.testing.node", "+net.corda.node.services.messaging")
@ -83,7 +79,7 @@ class TimedFlowTests {
mockNet.stopNodes() mockNet.stopNodes()
} }
private fun startClusterAndNode(mockNet: InternalMockNetwork): Pair<Party, StartedNode> { private fun startClusterAndNode(mockNet: InternalMockNetwork): Pair<Party, TestStartedNode> {
val replicaIds = (0 until CLUSTER_SIZE) val replicaIds = (0 until CLUSTER_SIZE)
val notaryIdentity = DevIdentityGenerator.generateDistributedNotaryCompositeIdentity( val notaryIdentity = DevIdentityGenerator.generateDistributedNotaryCompositeIdentity(
replicaIds.map { mockNet.baseDirectory(mockNet.nextNodeId + it) }, replicaIds.map { mockNet.baseDirectory(mockNet.nextNodeId + it) },
@ -164,7 +160,7 @@ class TimedFlowTests {
} }
} }
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction { private fun TestStartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction( return services.signInitialTransaction(
TransactionBuilder(notary).apply { TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey)) addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -16,17 +16,13 @@ import net.corda.core.node.services.vault.Sort
import net.corda.core.node.services.vault.SortAttribute import net.corda.core.node.services.vault.SortAttribute
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.node.services.statemachine.StateMachineManager import net.corda.node.services.statemachine.StateMachineManager
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.core.ALICE_NAME 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.internal.cordappsForPackages import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.junit.After import org.junit.After
import org.junit.Assert.* import org.junit.Assert.*
import org.junit.Before import org.junit.Before
@ -42,8 +38,8 @@ class ScheduledFlowTests {
} }
private lateinit var mockNet: InternalMockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: StartedNode private lateinit var bobNode: TestStartedNode
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

View File

@ -27,7 +27,6 @@ import net.corda.core.utilities.ProgressTracker.Change
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.InitiatedFlowFactory import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode
import net.corda.node.services.persistence.checkpoints import net.corda.node.services.persistence.checkpoints
import net.corda.testing.contracts.DummyContract import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyState import net.corda.testing.contracts.DummyState
@ -445,7 +444,7 @@ class FlowFrameworkTests {
private val normalEnd = ExistingSessionMessage(SessionId(0), EndSessionMessage) // NormalSessionEnd(0) private val normalEnd = ExistingSessionMessage(SessionId(0), EndSessionMessage) // NormalSessionEnd(0)
private fun StartedNode.sendSessionMessage(message: SessionMessage, destination: Party) { private fun TestStartedNode.sendSessionMessage(message: SessionMessage, destination: Party) {
services.networkService.apply { services.networkService.apply {
val address = getAddressOfParty(PartyInfo.SingleNode(destination, emptyList())) val address = getAddressOfParty(PartyInfo.SingleNode(destination, emptyList()))
send(createMessage(FlowMessagingImpl.sessionTopic, message.serialize().bytes), address) send(createMessage(FlowMessagingImpl.sessionTopic, message.serialize().bytes), address)
@ -774,7 +773,7 @@ class FlowFrameworkPersistenceTests {
private fun sessionConfirm(flowVersion: Int = 1) = ExistingSessionMessage(SessionId(0), ConfirmSessionMessage(SessionId(0), FlowInfo(flowVersion, ""))) private fun sessionConfirm(flowVersion: Int = 1) = ExistingSessionMessage(SessionId(0), ConfirmSessionMessage(SessionId(0), FlowInfo(flowVersion, "")))
private inline fun <reified P : FlowLogic<*>> StartedNode.getSingleFlow(): Pair<P, CordaFuture<*>> { private inline fun <reified P : FlowLogic<*>> TestStartedNode.getSingleFlow(): Pair<P, CordaFuture<*>> {
return smm.findStateMachines(P::class.java).single() return smm.findStateMachines(P::class.java).single()
} }
@ -809,7 +808,7 @@ private fun Observable<MessageTransfer>.toSessionTransfers(): Observable<Session
private fun errorMessage(errorResponse: FlowException? = null) = ExistingSessionMessage(SessionId(0), ErrorSessionMessage(errorResponse, 0)) private fun errorMessage(errorResponse: FlowException? = null) = ExistingSessionMessage(SessionId(0), ErrorSessionMessage(errorResponse, 0))
private infix fun TestStartedNode.sent(message: SessionMessage): Pair<Int, SessionMessage> = Pair(internals.id, message) private infix fun TestStartedNode.sent(message: SessionMessage): Pair<Int, SessionMessage> = Pair(internals.id, message)
private infix fun Pair<Int, SessionMessage>.to(node: StartedNode): SessionTransfer = SessionTransfer(first, second, node.network.myAddress) private infix fun Pair<Int, SessionMessage>.to(node: TestStartedNode): SessionTransfer = SessionTransfer(first, second, node.network.myAddress)
private data class SessionTransfer(val from: Int, val message: SessionMessage, val to: MessageRecipients) { private data class SessionTransfer(val from: Int, val message: SessionMessage, val to: MessageRecipients) {
val isPayloadTransfer: Boolean get() = val isPayloadTransfer: Boolean get() =

View File

@ -11,13 +11,9 @@ import net.corda.core.internal.IdempotentFlow
import net.corda.core.internal.TimedFlow import net.corda.core.internal.TimedFlow
import net.corda.core.internal.packageName import net.corda.core.internal.packageName
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.FlowTimeoutConfiguration import net.corda.node.services.config.FlowTimeoutConfiguration
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -27,8 +23,8 @@ import kotlin.test.assertEquals
class IdempotentFlowTests { class IdempotentFlowTests {
private lateinit var mockNet: InternalMockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var nodeA: StartedNode private lateinit var nodeA: TestStartedNode
private lateinit var nodeB: StartedNode private lateinit var nodeB: TestStartedNode
companion object { companion object {
val executionCounter = AtomicInteger(0) val executionCounter = AtomicInteger(0)

View File

@ -11,7 +11,6 @@ import net.corda.core.messaging.MessageRecipients
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.node.internal.StartedNode
import net.corda.node.services.FinalityHandler import net.corda.node.services.FinalityHandler
import net.corda.node.services.messaging.Message import net.corda.node.services.messaging.Message
import net.corda.node.services.persistence.DBTransactionStorage import net.corda.node.services.persistence.DBTransactionStorage
@ -53,7 +52,7 @@ class RetryFlowMockTest {
KeepSendingFlow.count.set(0) KeepSendingFlow.count.set(0)
} }
private fun <T> StartedNode.startFlow(logic: FlowLogic<T>): CordaFuture<T> { private fun <T> TestStartedNode.startFlow(logic: FlowLogic<T>): CordaFuture<T> {
return this.services.startFlow(logic, this.services.newContext()).flatMap { it.resultFuture } return this.services.startFlow(logic, this.services.newContext()).flatMap { it.resultFuture }
} }

View File

@ -10,15 +10,11 @@ import net.corda.core.internal.NotaryChangeTransactionBuilder
import net.corda.core.node.ServiceHub import net.corda.core.node.ServiceHub
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.node.internal.StartedNode
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.singleIdentity import net.corda.testing.core.singleIdentity
import net.corda.testing.node.MockNetworkNotarySpec import net.corda.testing.node.MockNetworkNotarySpec
import net.corda.testing.node.internal.cordappsForPackages import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -27,7 +23,7 @@ import kotlin.test.assertFailsWith
class NotaryServiceTests { class NotaryServiceTests {
private lateinit var mockNet: InternalMockNetwork private lateinit var mockNet: InternalMockNetwork
private lateinit var notaryServices: ServiceHub private lateinit var notaryServices: ServiceHub
private lateinit var aliceNode: StartedNode private lateinit var aliceNode: TestStartedNode
private lateinit var notary: Party private lateinit var notary: Party
private lateinit var alice: Party private lateinit var alice: Party
@ -55,7 +51,7 @@ class NotaryServiceTests {
internal companion object { internal companion object {
/** This is used by both [NotaryServiceTests] and [ValidatingNotaryServiceTests]. */ /** This is used by both [NotaryServiceTests] and [ValidatingNotaryServiceTests]. */
fun notariseWithTooManyInputs(node: StartedNode, party: Party, notary: Party, network: InternalMockNetwork) { fun notariseWithTooManyInputs(node: TestStartedNode, party: Party, notary: Party, network: InternalMockNetwork) {
val stx = generateTransaction(node, party, notary) val stx = generateTransaction(node, party, notary)
val future = node.services.startFlow(DummyClientFlow(stx, notary)).resultFuture val future = node.services.startFlow(DummyClientFlow(stx, notary)).resultFuture
@ -63,7 +59,7 @@ class NotaryServiceTests {
assertFailsWith<NotaryException> { future.getOrThrow() } assertFailsWith<NotaryException> { future.getOrThrow() }
} }
private fun generateTransaction(node: StartedNode, party: Party, notary: Party): SignedTransaction { private fun generateTransaction(node: TestStartedNode, party: Party, notary: Party): SignedTransaction {
val txHash = SecureHash.randomSHA256() val txHash = SecureHash.randomSHA256()
val inputs = (1..10_005).map { StateRef(txHash, it) } val inputs = (1..10_005).map { StateRef(txHash, it) }
val tx = NotaryChangeTransactionBuilder(inputs, notary, party).build() val tx = NotaryChangeTransactionBuilder(inputs, notary, party).build()

View File

@ -4,7 +4,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.messaging.CordaRPCOps import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NodeInfo import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.StartedNodeWithInternals import net.corda.node.internal.NodeWithInfo
import net.corda.node.services.api.StartedNodeServices import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.NodeConfiguration import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.persistence.CordaPersistence import net.corda.nodeapi.internal.persistence.CordaPersistence
@ -55,9 +55,9 @@ data class InProcessImpl(
override val useHTTPS: Boolean, override val useHTTPS: Boolean,
private val nodeThread: Thread, private val nodeThread: Thread,
private val onStopCallback: () -> Unit, private val onStopCallback: () -> Unit,
private val node: StartedNodeWithInternals private val node: NodeWithInfo
) : InProcess, NodeHandleInternal { ) : InProcess, NodeHandleInternal {
val database: CordaPersistence = node.database val database: CordaPersistence = node.node.database
override val services: StartedNodeServices get() = node.services override val services: StartedNodeServices get() = node.services
override val rpcUsers: List<User> = configuration.rpcUsers.map { User(it.username, it.password, it.permissions) } override val rpcUsers: List<User> = configuration.rpcUsers.map { User(it.username, it.password, it.permissions) }
override fun stop() { override fun stop() {

View File

@ -25,7 +25,7 @@ import net.corda.core.utilities.millis
import net.corda.node.NodeRegistrationOption import net.corda.node.NodeRegistrationOption
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
import net.corda.node.internal.Node import net.corda.node.internal.Node
import net.corda.node.internal.StartedNodeWithInternals import net.corda.node.internal.NodeWithInfo
import net.corda.node.services.Permissions import net.corda.node.services.Permissions
import net.corda.node.services.config.* import net.corda.node.services.config.*
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
@ -783,7 +783,7 @@ class DriverDSLImpl(
private fun startInProcessNode( private fun startInProcessNode(
executorService: ScheduledExecutorService, executorService: ScheduledExecutorService,
config: NodeConfig config: NodeConfig
): CordaFuture<Pair<StartedNodeWithInternals, Thread>> { ): CordaFuture<Pair<NodeWithInfo, Thread>> {
return executorService.fork { return executorService.fork {
log.info("Starting in-process Node ${config.corda.myLegalName.organisation}") log.info("Starting in-process Node ${config.corda.myLegalName.organisation}")
if (!(ManagementFactory.getRuntimeMXBean().inputArguments.any { it.contains("quasar") })) { if (!(ManagementFactory.getRuntimeMXBean().inputArguments.any { it.contains("quasar") })) {
@ -792,12 +792,13 @@ class DriverDSLImpl(
// Write node.conf // Write node.conf
writeConfig(config.corda.baseDirectory, "node.conf", config.typesafe.toNodeOnly()) writeConfig(config.corda.baseDirectory, "node.conf", config.typesafe.toNodeOnly())
// TODO pass the version in? // TODO pass the version in?
val internals = InProcessNode(config.corda, MOCK_VERSION_INFO) val node = InProcessNode(config.corda, MOCK_VERSION_INFO)
val node = internals.start() as StartedNodeWithInternals val nodeInfo = node.start()
val nodeWithInfo = NodeWithInfo(node, nodeInfo)
val nodeThread = thread(name = config.corda.myLegalName.organisation) { val nodeThread = thread(name = config.corda.myLegalName.organisation) {
internals.run() node.run()
} }
node to nodeThread nodeWithInfo to nodeThread
}.flatMap { nodeAndThread -> }.flatMap { nodeAndThread ->
addressMustBeBoundFuture(executorService, config.corda.p2pAddress).map { nodeAndThread } addressMustBeBoundFuture(executorService, config.corda.p2pAddress).map { nodeAndThread }
} }

View File

@ -9,6 +9,7 @@ import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.random63BitValue import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowLogic import net.corda.core.flows.FlowLogic
import net.corda.core.flows.InitiatedBy
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,7 +29,6 @@ import net.corda.node.VersionInfo
import net.corda.node.cordapp.CordappLoader import net.corda.node.cordapp.CordappLoader
import net.corda.node.internal.AbstractNode import net.corda.node.internal.AbstractNode
import net.corda.node.internal.InitiatedFlowFactory import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode
import net.corda.node.internal.cordapp.JarScanningCordappLoader import net.corda.node.internal.cordapp.JarScanningCordappLoader
import net.corda.node.services.api.FlowStarter import net.corda.node.services.api.FlowStarter
import net.corda.node.services.api.ServiceHubInternal import net.corda.node.services.api.ServiceHubInternal
@ -102,8 +102,25 @@ data class InternalMockNodeParameters(
/** /**
* A [StartedNode] which exposes its internal [InternalMockNetwork.MockNode] for testing. * A [StartedNode] which exposes its internal [InternalMockNetwork.MockNode] for testing.
*/ */
interface TestStartedNode : StartedNode { interface TestStartedNode {
val internals: InternalMockNetwork.MockNode val internals: InternalMockNetwork.MockNode
val info: NodeInfo
val services: StartedNodeServices
val smm: StateMachineManager
val attachments: NodeAttachmentService
val rpcOps: CordaRPCOps
val network: MessagingService
val database: CordaPersistence
val notaryService: NotaryService?
fun dispose() = internals.stop()
/**
* Use this method to register your initiated flows in your tests. This is automatically done by the node when it
* starts up for all [FlowLogic] classes it finds which are annotated with [InitiatedBy].
* @return An [Observable] of the initiated flows started by counterparties.
*/
fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T>
fun <F : FlowLogic<*>> internalRegisterFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>, fun <F : FlowLogic<*>> internalRegisterFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>, flowFactory: InitiatedFlowFactory<F>,

View File

@ -10,9 +10,9 @@ import net.corda.core.node.NodeInfo
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor import net.corda.core.utilities.loggerFor
import net.corda.node.VersionInfo import net.corda.node.VersionInfo
import net.corda.node.internal.NodeWithInfo
import net.corda.node.internal.Node import net.corda.node.internal.Node
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.config.* import net.corda.node.services.config.*
import net.corda.nodeapi.internal.config.toConfig import net.corda.nodeapi.internal.config.toConfig
import net.corda.nodeapi.internal.network.NetworkParametersCopier import net.corda.nodeapi.internal.network.NetworkParametersCopier
@ -47,7 +47,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
val tempFolder = TemporaryFolder() val tempFolder = TemporaryFolder()
private lateinit var defaultNetworkParameters: NetworkParametersCopier private lateinit var defaultNetworkParameters: NetworkParametersCopier
private val nodes = mutableListOf<StartedNodeWithInternals>() private val nodes = mutableListOf<NodeWithInfo>()
private val nodeInfos = mutableListOf<NodeInfo>() private val nodeInfos = mutableListOf<NodeInfo>()
private val portAllocation = PortAllocation.Incremental(10000) private val portAllocation = PortAllocation.Incremental(10000)
@ -72,8 +72,8 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
// Wait until ports are released // Wait until ports are released
val portNotBoundChecks = nodes.flatMap { val portNotBoundChecks = nodes.flatMap {
listOf( listOf(
addressMustNotBeBoundFuture(shutdownExecutor, it.internals.configuration.p2pAddress), addressMustNotBeBoundFuture(shutdownExecutor, it.node.configuration.p2pAddress),
addressMustNotBeBoundFuture(shutdownExecutor, it.internals.configuration.rpcOptions.address) addressMustNotBeBoundFuture(shutdownExecutor, it.node.configuration.rpcOptions.address)
) )
} }
nodes.clear() nodes.clear()
@ -87,7 +87,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
fun startNode(legalName: CordaX500Name, fun startNode(legalName: CordaX500Name,
platformVersion: Int = 1, platformVersion: Int = 1,
rpcUsers: List<User> = emptyList(), rpcUsers: List<User> = emptyList(),
configOverrides: Map<String, Any> = emptyMap()): StartedNodeWithInternals { configOverrides: Map<String, Any> = emptyMap()): NodeWithInfo {
val baseDirectory = baseDirectory(legalName).createDirectories() val baseDirectory = baseDirectory(legalName).createDirectories()
val p2pAddress = configOverrides["p2pAddress"] ?: portAllocation.nextHostAndPort().toString() val p2pAddress = configOverrides["p2pAddress"] ?: portAllocation.nextHostAndPort().toString()
val config = ConfigHelper.loadConfig( val config = ConfigHelper.loadConfig(
@ -119,15 +119,16 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
} }
defaultNetworkParameters.install(baseDirectory) defaultNetworkParameters.install(baseDirectory)
val internals = InProcessNode(parsedConfig, MOCK_VERSION_INFO.copy(platformVersion = platformVersion)) val node = InProcessNode(parsedConfig, MOCK_VERSION_INFO.copy(platformVersion = platformVersion))
val node = internals.start() as StartedNodeWithInternals val nodeInfo = node.start()
nodes += node val nodeWithInfo = NodeWithInfo(node, nodeInfo)
nodes += nodeWithInfo
ensureAllNetworkMapCachesHaveAllNodeInfos() ensureAllNetworkMapCachesHaveAllNodeInfos()
thread(name = legalName.organisation) { thread(name = legalName.organisation) {
internals.run() node.run()
} }
return node return nodeWithInfo
} }
protected fun baseDirectory(legalName: CordaX500Name): Path { protected fun baseDirectory(legalName: CordaX500Name): Path {
@ -135,7 +136,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
} }
private fun ensureAllNetworkMapCachesHaveAllNodeInfos() { private fun ensureAllNetworkMapCachesHaveAllNodeInfos() {
val runningNodes = nodes.filter { it.internals.started != null } val runningNodes = nodes.filter { it.node.started != null }
val runningNodesInfo = runningNodes.map { it.info } val runningNodesInfo = runningNodes.map { it.info }
for (node in runningNodes) for (node in runningNodes)
for (nodeInfo in runningNodesInfo) { for (nodeInfo in runningNodesInfo) {