CORDA-916 separate test startednode (#3675)

* Push start() implementation back into base

* Narrow access

* Optimise imports

* Fix tests

* Get Java test compiling
This commit is contained in:
Dominic Fox 2018-07-25 10:05:50 +01:00 committed by GitHub
parent 121dbec877
commit 6b320026a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 308 additions and 228 deletions

View File

@ -8,8 +8,8 @@ import net.corda.finance.flows.AbstractCashFlow;
import net.corda.finance.flows.CashIssueFlow;
import net.corda.finance.flows.CashPaymentFlow;
import net.corda.finance.schemas.CashSchemaV1;
import net.corda.node.internal.Node;
import net.corda.node.internal.StartedNode;
import net.corda.node.internal.StartedNodeWithInternals;
import net.corda.testing.internal.InternalTestUtilsKt;
import net.corda.testing.node.User;
import net.corda.testing.node.internal.NodeBasedTest;
@ -44,7 +44,7 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
private Set<String> permSet = new HashSet<>(perms);
private User rpcUser = new User("user1", "test", permSet);
private StartedNode<Node> node;
private StartedNodeWithInternals node;
private CordaRPCClient client;
private RPCConnection<CordaRPCOps> connection = null;
private CordaRPCOps rpcProxy;

View File

@ -20,8 +20,7 @@ import net.corda.finance.contracts.getCashBalance
import net.corda.finance.contracts.getCashBalances
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions.Companion.all
import net.corda.testing.common.internal.checkNotOnClasspath
import net.corda.testing.core.*
@ -51,7 +50,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance")) {
val rpcUser = User("user1", "test", permissions = setOf(all()))
}
private lateinit var node: StartedNode<Node>
private lateinit var node: StartedNodeWithInternals
private lateinit var identity: Party
private lateinit var client: CordaRPCClient
private var connection: CordaRPCConnection? = null

View File

@ -6,8 +6,7 @@ import net.corda.core.internal.packageName
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.getOrThrow
import net.corda.finance.schemas.CashSchemaV1
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions
import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.testing.core.ALICE_NAME
@ -49,7 +48,7 @@ class FlowsExecutionModeRpcTest {
class FlowsExecutionModeTests : NodeBasedTest(listOf("net.corda.finance.contracts", CashSchemaV1::class.packageName)) {
private val rpcUser = User("user1", "test", permissions = setOf(Permissions.all()))
private lateinit var node: StartedNode<Node>
private lateinit var node: StartedNodeWithInternals
private lateinit var client: CordaRPCClient
@Before

View File

@ -1,8 +1,9 @@
package net.corda.core.crypto;
import net.corda.core.KeepForDJVM;
import java.math.*;
import java.util.*;
import java.math.BigInteger;
import java.util.Arrays;
/**
* Base58 is a way to encode Bitcoin addresses (or arbitrary data) as alphanumeric strings.

View File

@ -1,6 +1,6 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
/**

View File

@ -1,9 +1,7 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
import kotlin.annotation.Retention
import kotlin.annotation.Target
/**
* Declare the annotated element to unsuitable for the deterministic version of Corda.

View File

@ -1,9 +1,8 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationTarget.*
import kotlin.annotation.Retention
import kotlin.annotation.Target
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FILE
/**
* This annotates a class or file that we want to include into the deterministic version of Corda Core.

View File

@ -1,9 +1,7 @@
package net.corda.core
import kotlin.annotation.AnnotationRetention.*
import kotlin.annotation.AnnotationRetention.BINARY
import kotlin.annotation.AnnotationTarget.*
import kotlin.annotation.Retention
import kotlin.annotation.Target
/**
* We expect that almost every non-deterministic element can have its bytecode

View File

@ -1,9 +1,9 @@
@file:JvmName("ConcurrencyUtils")
package net.corda.core.concurrent
import net.corda.core.internal.VisibleForTesting
import net.corda.core.internal.concurrent.openFuture
import net.corda.core.utilities.getOrThrow
import net.corda.core.internal.VisibleForTesting
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.concurrent.Future

View File

@ -1,10 +1,10 @@
package net.corda.core.crypto
import net.corda.core.KeepForDJVM
import net.corda.core.StubOutForDJVM
import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_KEY
import net.corda.core.crypto.CordaObjectIdentifier.COMPOSITE_SIGNATURE
import org.bouncycastle.asn1.ASN1ObjectIdentifier
import net.corda.core.StubOutForDJVM
import java.security.Provider
@KeepForDJVM

View File

@ -14,7 +14,10 @@ import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.SerializationDefaults
import net.corda.core.serialization.serialize
import net.corda.core.transactions.SignedTransaction
import net.corda.core.utilities.*
import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.UntrustworthyData
import net.corda.core.utilities.debug
import net.corda.core.utilities.toNonEmptySet
import org.slf4j.Logger
import java.time.Duration

View File

@ -3,8 +3,8 @@ package net.corda.core.identity
import net.corda.core.KeepForDJVM
import net.corda.core.internal.LegalNameValidator
import net.corda.core.internal.toAttributesMap
import net.corda.core.internal.unspecifiedCountry
import net.corda.core.internal.toX500Name
import net.corda.core.internal.unspecifiedCountry
import net.corda.core.serialization.CordaSerializable
import org.bouncycastle.asn1.x500.style.BCStyle
import java.util.*

View File

@ -5,7 +5,10 @@ import net.corda.core.DeleteForDJVM
import net.corda.core.DoNotImplement
import net.corda.core.concurrent.CordaFuture
import net.corda.core.context.InvocationContext
import net.corda.core.flows.*
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.FlowSession
import net.corda.core.flows.FlowStackSnapshot
import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.Party
import net.corda.core.node.ServiceHub
import org.slf4j.Logger

View File

@ -1,8 +1,8 @@
package net.corda.core.internal.concurrent
import net.corda.core.internal.VisibleForTesting
import net.corda.core.concurrent.CordaFuture
import net.corda.core.concurrent.match
import net.corda.core.internal.VisibleForTesting
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.getOrThrow
import org.slf4j.Logger

View File

@ -4,18 +4,12 @@ import net.corda.core.internal.concurrent.OpenFuture;
import org.junit.Test;
import java.io.EOFException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.*;
import static net.corda.core.internal.concurrent.CordaFutureImplKt.doneFuture;
import static net.corda.core.internal.concurrent.CordaFutureImplKt.openFuture;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
public class CordaFutureInJavaTest {
@Test

View File

@ -148,18 +148,18 @@ class AttachmentTests : WithMockNet {
//endregion
//region Operations
private fun StartedNode<*>.importAttachment(attachment: ByteArray) =
private fun StartedNode.importAttachment(attachment: ByteArray) =
attachments.importAttachment(attachment.inputStream(), "test", null)
.andRunNetwork()
private fun StartedNode<*>.updateAttachment(attachment: NodeAttachmentService.DBAttachment) = database.transaction {
private fun StartedNode.updateAttachment(attachment: NodeAttachmentService.DBAttachment) = database.transaction {
session.update(attachment)
}.andRunNetwork()
private fun StartedNode<*>.startAttachmentFlow(hash: SecureHash, otherSide: Party) = startFlowAndRunNetwork(
private fun StartedNode.startAttachmentFlow(hash: SecureHash, otherSide: Party) = startFlowAndRunNetwork(
InitiatingFetchAttachmentsFlow(otherSide, setOf(hash)))
private fun StartedNode<*>.getAttachmentWithId(id: SecureHash) =
private fun StartedNode.getAttachmentWithId(id: SecureHash) =
attachments.openAttachment(id)!!
//endregion

View File

@ -93,7 +93,7 @@ class CollectSignaturesFlowTests : WithContracts {
}
//region Operators
private fun StartedNode<*>.startTestFlow(vararg party: Party) =
private fun StartedNode.startTestFlow(vararg party: Party) =
startFlowAndRunNetwork(
TestFlow.Initiator(DummyContract.MultiOwnerState(
MAGIC_NUMBER,

View File

@ -24,7 +24,6 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.User
import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import org.junit.AfterClass
import org.junit.Test
@ -85,7 +84,7 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
}
//region RPC DSL
private fun RPCDriverDSL.startProxy(node: StartedNode<MockNode>, user: User): CordaRPCOps {
private fun RPCDriverDSL.startProxy(node: StartedNode, user: User): CordaRPCOps {
return startRpcClient<CordaRPCOps>(
rpcAddress = startRpcServer(
rpcUser = user,
@ -113,16 +112,16 @@ class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
//endregion
//region Matchers
private fun StartedNode<*>.hasDummyContractUpgradeTransaction() =
private fun StartedNode.hasDummyContractUpgradeTransaction() =
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> StartedNode.hasContractUpgradeTransaction() =
has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>(
"a contract upgrade transaction",
{ getContractUpgradeTransaction(it) },
isUpgrade<FROM, TO>())
private fun StartedNode<*>.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
private fun StartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
services.validatedTransactions.getTransaction(state.ref.txhash)!!
.resolveContractUpgradeTransaction(services)

View File

@ -85,14 +85,14 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
and bobNode.hasDummyContractUpgradeTransaction()))
}
private fun StartedNode<*>.issueCash(amount: Amount<Currency> = Amount(1000, USD)) =
private fun StartedNode.issueCash(amount: Amount<Currency> = Amount(1000, USD)) =
services.startFlow(CashIssueFlow(amount, OpaqueBytes.of(1), notary))
.andRunNetwork()
.resultFuture.getOrThrow()
private fun StartedNode<*>.getBaseStateFromVault() = getStateFromVault(ContractState::class)
private fun StartedNode.getBaseStateFromVault() = getStateFromVault(ContractState::class)
private fun StartedNode<*>.getCashStateFromVault() = getStateFromVault(CashV2.State::class)
private fun StartedNode.getCashStateFromVault() = getStateFromVault(CashV2.State::class)
private fun hasIssuedAmount(expected: Amount<Issued<Currency>>) =
hasContractState(has(CashV2.State::amount, equalTo(expected)))
@ -162,24 +162,24 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
}
//region Operations
private fun StartedNode<*>.initiateDummyContractUpgrade(tx: SignedTransaction) =
private fun StartedNode.initiateDummyContractUpgrade(tx: SignedTransaction) =
initiateContractUpgrade(tx, DummyContractV2::class)
private fun StartedNode<*>.authoriseDummyContractUpgrade(tx: SignedTransaction) =
private fun StartedNode.authoriseDummyContractUpgrade(tx: SignedTransaction) =
authoriseContractUpgrade(tx, DummyContractV2::class)
//endregion
//region Matchers
private fun StartedNode<*>.hasDummyContractUpgradeTransaction() =
private fun StartedNode.hasDummyContractUpgradeTransaction() =
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> StartedNode.hasContractUpgradeTransaction() =
has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>(
"a contract upgrade transaction",
{ getContractUpgradeTransaction(it) },
isUpgrade<FROM, TO>())
private fun StartedNode<*>.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
private fun StartedNode.getContractUpgradeTransaction(state: StateAndRef<ContractState>) =
services.validatedTransactions.getTransaction(state.ref.txhash)!!
.resolveContractUpgradeTransaction(services)

View File

@ -58,7 +58,7 @@ class FinalityFlowTests : WithFinality {
willThrow<IllegalArgumentException>())
}
private fun StartedNode<*>.signCashTransactionWith(other: Party): SignedTransaction {
private fun StartedNode.signCashTransactionWith(other: Party): SignedTransaction {
val amount = 1000.POUNDS.issuedBy(alice.ref(0))
val builder = TransactionBuilder(notary)
Cash().generateIssue(builder, amount, other, notary)

View File

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

View File

@ -2,8 +2,6 @@ package net.corda.core.flows
import co.paralleluniverse.fibers.Suspendable
import com.natpryce.hamkrest.assertion.assert
import com.natpryce.hamkrest.equalTo
import com.natpryce.hamkrest.isA
import net.corda.core.flows.matchers.flow.willReturn
import net.corda.core.flows.mixins.WithMockNet
import net.corda.core.identity.Party

View File

@ -3,8 +3,8 @@ package net.corda.core.flows.matchers.flow
import com.natpryce.hamkrest.Matcher
import com.natpryce.hamkrest.equalTo
import com.natpryce.hamkrest.has
import net.corda.core.flows.matchers.willThrow
import net.corda.core.flows.matchers.willReturn
import net.corda.core.flows.matchers.willThrow
import net.corda.core.internal.FlowStateMachine
/**

View File

@ -2,8 +2,8 @@ package net.corda.core.flows.matchers.rpc
import com.natpryce.hamkrest.Matcher
import com.natpryce.hamkrest.has
import net.corda.core.flows.matchers.willThrow
import net.corda.core.flows.matchers.willReturn
import net.corda.core.flows.matchers.willThrow
import net.corda.core.messaging.FlowHandle
/**

View File

@ -29,33 +29,33 @@ interface WithContracts : WithMockNet {
//region
//region Operations
fun StartedNode<*>.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
fun StartedNode.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
services.signDummyContract(owner, magicNumber, *others).andRunNetwork()
fun ServiceHub.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
signInitialTransaction(createDummyContract(owner, magicNumber, *others))
fun StartedNode<*>.collectSignatures(ptx: SignedTransaction) =
fun StartedNode.collectSignatures(ptx: SignedTransaction) =
startFlowAndRunNetwork(CollectSignaturesFlow(ptx, emptySet()))
fun StartedNode<*>.addSignatureTo(ptx: SignedTransaction) =
fun StartedNode.addSignatureTo(ptx: SignedTransaction) =
services.addSignature(ptx).andRunNetwork()
fun <T : UpgradedContract<*, *>>
StartedNode<*>.initiateContractUpgrade(tx: SignedTransaction, toClass: KClass<T>) =
StartedNode.initiateContractUpgrade(tx: SignedTransaction, toClass: KClass<T>) =
initiateContractUpgrade(tx.tx.outRef(0), toClass)
fun <S : ContractState, T : UpgradedContract<S, *>>
StartedNode<*>.initiateContractUpgrade(stateAndRef: StateAndRef<S>, toClass: KClass<T>) =
StartedNode.initiateContractUpgrade(stateAndRef: StateAndRef<S>, toClass: KClass<T>) =
startFlowAndRunNetwork(ContractUpgradeFlow.Initiate(stateAndRef, toClass.java))
fun <T : UpgradedContract<*, *>> StartedNode<*>.authoriseContractUpgrade(
fun <T : UpgradedContract<*, *>> StartedNode.authoriseContractUpgrade(
tx: SignedTransaction, toClass: KClass<T>) =
startFlow(
ContractUpgradeFlow.Authorise(tx.tx.outRef<ContractState>(0), toClass.java)
)
fun StartedNode<*>.deauthoriseContractUpgrade(tx: SignedTransaction) = startFlow(
fun StartedNode.deauthoriseContractUpgrade(tx: SignedTransaction) = startFlow(
ContractUpgradeFlow.Deauthorise(tx.tx.outRef<ContractState>(0).ref)
)

View File

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

View File

@ -41,32 +41,32 @@ interface WithMockNet {
/**
* Sign an initial transaction
*/
fun StartedNode<*>.signInitialTransaction(build: TransactionBuilder.() -> TransactionBuilder) =
fun StartedNode.signInitialTransaction(build: TransactionBuilder.() -> TransactionBuilder) =
services.signInitialTransaction(TransactionBuilder(mockNet.defaultNotaryIdentity).build())
/**
* 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> StartedNode.getStateFromVault(stateClass: KClass<S>) =
services.vaultService.queryBy(stateClass.java).states.single()
/**
* Start a flow
*/
fun <T> StartedNode<*>.startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = services.startFlow(logic)
fun <T> StartedNode.startFlow(logic: FlowLogic<T>): FlowStateMachine<T> = services.startFlow(logic)
/**
* Start a flow and run the network immediately afterwards
*/
fun <T> StartedNode<*>.startFlowAndRunNetwork(logic: FlowLogic<T>): FlowStateMachine<T> =
fun <T> StartedNode.startFlowAndRunNetwork(logic: FlowLogic<T>): FlowStateMachine<T> =
startFlow(logic).andRunNetwork()
fun StartedNode<*>.createConfidentialIdentity(party: Party) =
fun StartedNode.createConfidentialIdentity(party: Party) =
services.keyManagementService.freshKeyAndCert(
services.myInfo.legalIdentitiesAndCerts.single { it.name == party.name },
false)
fun StartedNode<*>.verifyAndRegister(identity: PartyAndCertificate) =
fun StartedNode.verifyAndRegister(identity: PartyAndCertificate) =
services.identityService.verifyAndRegisterIdentity(identity)
//endregion

View File

@ -21,6 +21,7 @@ import net.corda.testing.core.BOB_NAME
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow
import org.junit.After
import org.junit.Before
@ -44,11 +45,11 @@ private fun
Attachment.extractContent() = ByteArrayOutputStream().apply { extractFile("content", this) }.toString(UTF_8.name())
@Suppress("deprecation")
private fun StartedNode<*>.saveAttachment(content: String) = database.transaction {
private fun StartedNode.saveAttachment(content: String) = database.transaction {
attachments.importAttachment(createAttachmentData(content).inputStream())
}
private fun StartedNode<*>.hackAttachment(attachmentId: SecureHash, content: String) = database.transaction {
private fun StartedNode.hackAttachment(attachmentId: SecureHash, content: String) = database.transaction {
updateAttachment(attachmentId, createAttachmentData(content))
}
@ -66,8 +67,8 @@ private fun updateAttachment(attachmentId: SecureHash, data: ByteArray) {
class AttachmentSerializationTest {
private lateinit var mockNet: InternalMockNetwork
private lateinit var server: StartedNode<InternalMockNetwork.MockNode>
private lateinit var client: StartedNode<InternalMockNetwork.MockNode>
private lateinit var server: TestStartedNode
private lateinit var client: TestStartedNode
private lateinit var serverIdentity: Party
@Before

View File

@ -10,8 +10,8 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
import net.corda.finance.flows.CashIssueFlow
import net.corda.node.internal.DataSourceFactory
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.Permissions
import net.corda.node.services.config.PasswordEncryption
import net.corda.testing.node.internal.NodeBasedTest
@ -35,7 +35,7 @@ import kotlin.test.assertFailsWith
@RunWith(Parameterized::class)
class AuthDBTests : NodeBasedTest() {
private lateinit var node: StartedNode<Node>
private lateinit var node: StartedNodeWithInternals
private lateinit var client: CordaRPCClient
private lateinit var db: UsersDB

View File

@ -35,7 +35,6 @@ import net.corda.testing.core.singleIdentity
import net.corda.testing.node.TestClock
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.hamcrest.Matchers.instanceOf
@ -57,7 +56,7 @@ class BFTNotaryServiceTests {
companion object {
private lateinit var mockNet: InternalMockNetwork
private lateinit var notary: Party
private lateinit var node: StartedNode<MockNode>
private lateinit var node: StartedNode
@BeforeClass
@JvmStatic
@ -75,7 +74,7 @@ class BFTNotaryServiceTests {
mockNet.stopNodes()
}
fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair<Party, StartedNode<MockNode>> {
fun startBftClusterAndNode(clusterSize: Int, mockNet: InternalMockNetwork, exposeRaces: Boolean = false): Pair<Party, StartedNode> {
(Paths.get("config") / "currentView").deleteIfExists() // XXX: Make config object warn if this exists?
val replicaIds = (0 until clusterSize)
@ -215,7 +214,7 @@ class BFTNotaryServiceTests {
signatures.forEach { it.verify(txId) }
}
private fun StartedNode<MockNode>.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction(
TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -14,7 +14,6 @@ import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.startFlow
import org.junit.After
import org.junit.Before
@ -49,7 +48,7 @@ class BFTSMaRtTests {
f.getOrThrow()
}
private fun StartedNode<MockNode>.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction(
TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

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

View File

@ -14,8 +14,7 @@ import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.nodeapi.RPCApi
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.INTERNAL_PREFIX
import net.corda.nodeapi.internal.ArtemisMessagingComponent.Companion.NOTIFICATIONS_ADDRESS
@ -26,6 +25,7 @@ import net.corda.testing.node.User
import net.corda.testing.core.singleIdentity
import net.corda.testing.internal.configureTestSSL
import net.corda.testing.node.internal.NodeBasedTest
import net.corda.testing.node.internal.TestStartedNode
import net.corda.testing.node.internal.startFlow
import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
@ -44,7 +44,7 @@ import kotlin.test.assertEquals
*/
abstract class MQSecurityTest : NodeBasedTest() {
val rpcUser = User("user1", "pass", permissions = emptySet())
lateinit var alice: StartedNode<Node>
lateinit var alice: StartedNodeWithInternals
lateinit var attacker: SimpleMQClient
private val clients = ArrayList<SimpleMQClient>()

View File

@ -110,24 +110,12 @@ 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
// AbstractNode. It should be possible to generate the NodeInfo outside of AbstractNode, so it can be passed in.
abstract class AbstractNode(val configuration: NodeConfiguration,
val platformClock: CordaClock,
protected val versionInfo: VersionInfo,
protected val cordappLoader: CordappLoader,
protected val serverThread: AffinityExecutor.ServiceAffinityExecutor,
private val busyNodeLatch: ReusableLatch = ReusableLatch()) : SingletonSerializeAsToken() {
private class StartedNodeImpl<out N : AbstractNode>(
override val internals: N,
override val info: NodeInfo,
override val rpcOps: CordaRPCOps,
override val notaryService: NotaryService?) : StartedNode<N> {
override val smm: StateMachineManager get() = internals.smm
override val attachments: NodeAttachmentService get() = internals.attachments
override val network: MessagingService get() = internals.network
override val database: CordaPersistence get() = internals.database
override val services: StartedNodeServices = object : StartedNodeServices, ServiceHubInternal by internals.services, FlowStarter by internals.flowStarter {}
}
abstract class AbstractNode<S : StartedNode>(val configuration: NodeConfiguration,
val platformClock: CordaClock,
protected val versionInfo: VersionInfo,
protected val cordappLoader: CordappLoader,
protected val serverThread: AffinityExecutor.ServiceAffinityExecutor,
private val busyNodeLatch: ReusableLatch = ReusableLatch()) : SingletonSerializeAsToken() {
protected abstract val log: Logger
@ -195,7 +183,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
val services = ServiceHubInternalImpl().tokenize()
@Suppress("LeakingThis")
val smm = makeStateMachineManager()
private val flowStarter = FlowStarterImpl(smm, flowLogicRefFactory)
protected val flowStarter = FlowStarterImpl(smm, flowLogicRefFactory)
private val schedulerService = NodeSchedulerService(
platformClock,
database,
@ -233,7 +221,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
/** Set to non-null once [start] has been successfully called. */
open val started get() = _started
@Volatile
private var _started: StartedNode<AbstractNode>? = null
private var _started: StartedNode? = null
private fun <T : Any> T.tokenize(): T {
tokenizableServices?.add(this) ?: throw IllegalStateException("The tokenisable services list has already been finialised")
@ -290,7 +278,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
}
}
open fun start(): StartedNode<AbstractNode> {
open fun start(): S {
check(started == null) { "Node has already been started" }
if (configuration.devMode) {
@ -371,10 +359,13 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
schedulerService.start()
StartedNodeImpl(this@AbstractNode, nodeInfo, rpcOps, notaryService).also { _started = it }
createStartedNode(nodeInfo, rpcOps, notaryService).also { _started = it }
}
}
/** Subclasses must override this to create a [StartedNode] of the desired type, using the provided machinery. */
abstract fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): S
private fun verifyCheckpointsCompatible(tokenizableServices: List<Any>) {
try {
CheckpointVerifier.verifyCheckpointsCompatible(checkpointStorage, cordappProvider.cordapps, versionInfo.platformVersion, services, tokenizableServices)
@ -634,7 +625,7 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
}
}
internal fun <T : FlowLogic<*>> registerInitiatedFlow(smm: StateMachineManager, initiatedFlowClass: Class<T>): Observable<T> {
protected fun <T : FlowLogic<*>> registerInitiatedFlow(smm: StateMachineManager, initiatedFlowClass: Class<T>): Observable<T> {
return registerInitiatedFlowInternal(smm, initiatedFlowClass, track = true)
}
@ -670,11 +661,11 @@ abstract class AbstractNode(val configuration: NodeConfiguration,
return observable
}
internal fun <F : FlowLogic<*>> internalRegisterFlowFactory(smm: StateMachineManager,
initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> {
protected fun <F : FlowLogic<*>> internalRegisterFlowFactory(smm: StateMachineManager,
initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> {
val observable = if (track) {
smm.changes.filter { it is StateMachineManager.Change.Add }.map { it.logic }.ofType(initiatedFlowClass)
} else {
@ -959,7 +950,7 @@ internal fun logVendorString(database: CordaPersistence, log: Logger) {
}
// TODO Move this into its own file
internal class FlowStarterImpl(private val smm: StateMachineManager, private val flowLogicRefFactory: FlowLogicRefFactory) : FlowStarter {
class FlowStarterImpl(private val smm: StateMachineManager, private val flowLogicRefFactory: FlowLogicRefFactory) : FlowStarter {
override fun <T> startFlow(event: ExternalEvent.ExternalStartFlowEvent<T>): CordaFuture<FlowStateMachine<T>> {
smm.deliverExternalEvent(event)
return event.future
@ -1042,4 +1033,4 @@ fun CordaPersistence.hikariStart(hikariProperties: Properties) {
else -> throw CouldNotCreateDataSourceException("Could not create the DataSource: ${ex.message}", ex)
}
}
}
}

View File

@ -3,6 +3,7 @@ package net.corda.node.internal
import com.codahale.metrics.JmxReporter
import net.corda.client.rpc.internal.serialization.amqp.AMQPClientSerializationScheme
import net.corda.core.concurrent.CordaFuture
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.Emoji
@ -10,7 +11,11 @@ import net.corda.core.internal.concurrent.openFuture
import net.corda.core.internal.concurrent.thenMatch
import net.corda.core.internal.div
import net.corda.core.internal.errors.AddressBindingException
import net.corda.core.internal.uncheckedCast
import net.corda.core.internal.notary.NotaryService
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.RPCOps
import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo
@ -33,6 +38,8 @@ import net.corda.node.serialization.amqp.AMQPServerSerializationScheme
import net.corda.node.serialization.kryo.KRYO_CHECKPOINT_CONTEXT
import net.corda.node.serialization.kryo.KryoServerSerializationScheme
import net.corda.node.services.Permissions
import net.corda.node.services.api.FlowStarter
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.SecurityConfiguration
import net.corda.node.services.config.shouldInitCrashShell
@ -60,6 +67,16 @@ import java.time.Clock
import java.util.concurrent.atomic.AtomicInteger
import javax.management.ObjectName
import kotlin.system.exitProcess
import net.corda.node.services.persistence.NodeAttachmentService
/**
* A version of [StartedNode] which exposes its [Node] internals.
*
* Although this is the type of [StartedNode] created by [Node], it is not explicitly provided
* and should not ordinarily be used (the code that _does_ use it obtains it via a cast).
*/
interface StartedNodeWithInternals : StartedNode {
val internals: Node
}
/**
* A Node manages a standalone server that takes part in the P2P network. It creates the services found in [ServiceHub],
@ -71,7 +88,7 @@ open class Node(configuration: NodeConfiguration,
versionInfo: VersionInfo,
private val initialiseSerialization: Boolean = true,
cordappLoader: CordappLoader = makeCordappLoader(configuration)
) : AbstractNode(
) : AbstractNode<StartedNode>(
configuration,
createClock(configuration),
versionInfo,
@ -79,6 +96,38 @@ open class Node(configuration: NodeConfiguration,
// Under normal (non-test execution) it will always be "1"
AffinityExecutor.ServiceAffinityExecutor("Node thread-${sameVmNodeCounter.incrementAndGet()}", 1)
) {
/** The actual [StartedNode] implementation created by this [AbstractNode]. */
private class StartedNodeWithInternalsImpl(
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 {
private val staticLog = contextLogger()
var renderBasicInfoToConsole = true
@ -350,9 +399,9 @@ open class Node(configuration: NodeConfiguration,
return super.generateAndSaveNodeInfo()
}
override fun start(): StartedNode<Node> {
override fun start(): StartedNode {
initialiseSerialization()
val started: StartedNode<Node> = uncheckedCast(super.start())
val started: StartedNode = super.start()
nodeReadyFuture.thenMatch({
serverThread.execute {
// Begin exporting our own metrics via JMX. These can be monitored using any agent, e.g. Jolokia:
@ -425,4 +474,4 @@ open class Node(configuration: NodeConfiguration,
log.info("Shutdown complete")
}
}
}

View File

@ -326,14 +326,14 @@ open class NodeStartup(val args: Array<String>) {
val startedNode = node.start()
Node.printBasicNodeInfo("Loaded CorDapps", startedNode.services.cordappProvider.cordapps.joinToString { it.name })
startedNode.internals.nodeReadyFuture.thenMatch({
node.nodeReadyFuture.thenMatch({
val elapsed = (System.currentTimeMillis() - startTime) / 10 / 100.0
val name = startedNode.info.legalIdentitiesAndCerts.first().name.organisation
Node.printBasicNodeInfo("Node for \"$name\" started up and registered in $elapsed sec")
// Don't start the shell if there's no console attached.
if (conf.shouldStartLocalShell()) {
startedNode.internals.startupComplete.then {
node.startupComplete.then {
try {
InteractiveShell.runLocalShell({ startedNode.dispose() })
} catch (e: Throwable) {
@ -348,7 +348,7 @@ open class NodeStartup(val args: Array<String>) {
{ th ->
logger.error("Unexpected exception during registration", th)
})
startedNode.internals.run()
node.run()
}
protected open fun logStartupInfo(versionInfo: VersionInfo, cmdlineOptions: CmdLineOptions, conf: NodeConfiguration) {

View File

@ -1,12 +1,15 @@
package net.corda.node.internal
import com.google.common.annotations.VisibleForTesting
interface NodeUniqueIdProvider {
val value: String
}
// this is stubbed because we still do not support clustered node setups.
// the moment we will, this will have to be changed to return a value unique for each physical node.
internal object StubbedNodeUniqueIdProvider : NodeUniqueIdProvider {
@VisibleForTesting
object StubbedNodeUniqueIdProvider : NodeUniqueIdProvider {
// TODO implement to return a value unique for each physical node when we will support clustered node setups.
override val value: String = "NABOB"

View File

@ -13,8 +13,7 @@ import net.corda.node.services.statemachine.StateMachineManager
import net.corda.nodeapi.internal.persistence.CordaPersistence
import rx.Observable
interface StartedNode<out N : AbstractNode> {
val internals: N
interface StartedNode {
val services: StartedNodeServices
val info: NodeInfo
val smm: StateMachineManager
@ -24,20 +23,12 @@ interface StartedNode<out N : AbstractNode> {
val rpcOps: CordaRPCOps
val notaryService: NotaryService?
fun dispose() = internals.stop()
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>) = internals.registerInitiatedFlow(smm, initiatedFlowClass)
@VisibleForTesting
fun <F : FlowLogic<*>> internalRegisterFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> {
return internals.internalRegisterFlowFactory(smm, initiatingFlowClass, flowFactory, initiatedFlowClass, track)
}
fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T>
}

View File

@ -41,7 +41,6 @@ import net.corda.testing.core.expectEvents
import net.corda.testing.core.sequence
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.testActor
import org.apache.commons.io.IOUtils
@ -72,7 +71,7 @@ class CordaRPCOpsImplTest {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var alice: Party
private lateinit var notary: Party
private lateinit var rpc: CordaRPCOps

View File

@ -44,7 +44,7 @@ class NodeTest {
}
}
private fun AbstractNode.generateNodeInfo(): NodeInfo {
private fun Node.generateNodeInfo(): NodeInfo {
assertNull(nodeInfoFile())
generateAndSaveNodeInfo()
val path = nodeInfoFile()!!

View File

@ -313,7 +313,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
// of gets and puts.
private fun makeNodeWithTracking(name: CordaX500Name): StartedNode<InternalMockNetwork.MockNode> {
private fun makeNodeWithTracking(name: CordaX500Name): StartedNode {
// Create a node in the mock network ...
return mockNet.createNode(InternalMockNodeParameters(legalName = name), nodeFactory = { args, cordappLoader ->
if (cordappLoader != null) {
@ -543,8 +543,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun runBuyerAndSeller(notary: Party,
buyer: Party,
sellerNode: StartedNode<InternalMockNetwork.MockNode>,
buyerNode: StartedNode<InternalMockNetwork.MockNode>,
sellerNode: StartedNode,
buyerNode: StartedNode,
assetToSell: StateAndRef<OwnableState>): RunResult {
val buyerFlows: Observable<out FlowLogic<*>> = buyerNode.registerInitiatedFlow(BuyerAcceptor::class.java)
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }
@ -638,10 +638,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun insertFakeTransactions(
wtxToSign: List<WireTransaction>,
node: StartedNode<*>,
node: StartedNode,
identity: Party,
notaryNode: StartedNode<*>,
vararg extraSigningNodes: StartedNode<*>): Map<SecureHash, SignedTransaction> {
notaryNode: StartedNode,
vararg extraSigningNodes: StartedNode): Map<SecureHash, SignedTransaction> {
val notaryParty = mockNet.defaultNotaryIdentity
val signed = wtxToSign.map {
val id = it.id

View File

@ -34,8 +34,8 @@ import kotlin.test.fail
class ScheduledFlowsDrainingModeTest {
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var bobNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var bobNode: StartedNode
private lateinit var notary: Party
private lateinit var alice: Party
private lateinit var bob: Party

View File

@ -75,7 +75,7 @@ class FinalityHandlerTest {
assertThat(bob.getTransaction(finalisedTx.id)).isNull()
}
private fun StartedNode<*>.assertFlowSentForObservation(runId: StateMachineRunId) {
private fun StartedNode.assertFlowSentForObservation(runId: StateMachineRunId) {
val keptInForObservation = smm.flowHospital
.track()
.let { it.updates.startWith(it.snapshot) }
@ -86,7 +86,7 @@ class FinalityHandlerTest {
assertThat(keptInForObservation.by).contains(StaffedFlowHospital.FinalityDoctor)
}
private fun StartedNode<*>.getTransaction(id: SecureHash): SignedTransaction? {
private fun StartedNode.getTransaction(id: SecureHash): SignedTransaction? {
return database.transaction {
services.validatedTransactions.getTransaction(id)
}

View File

@ -58,7 +58,7 @@ class TimedFlowTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var notary: Party
private lateinit var node: StartedNode<InternalMockNetwork.MockNode>
private lateinit var node: StartedNode
init {
LogHelper.setLevel("+net.corda.flow", "+net.corda.testing.node", "+net.corda.node.services.messaging")
@ -83,7 +83,7 @@ class TimedFlowTests {
mockNet.stopNodes()
}
private fun startClusterAndNode(mockNet: InternalMockNetwork): Pair<Party, StartedNode<InternalMockNetwork.MockNode>> {
private fun startClusterAndNode(mockNet: InternalMockNetwork): Pair<Party, StartedNode> {
val replicaIds = (0 until CLUSTER_SIZE)
val notaryIdentity = DevIdentityGenerator.generateDistributedNotaryCompositeIdentity(
replicaIds.map { mockNet.baseDirectory(mockNet.nextNodeId + it) },
@ -164,7 +164,7 @@ class TimedFlowTests {
}
}
private fun StartedNode<InternalMockNetwork.MockNode>.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
private fun StartedNode.signInitialTransaction(notary: Party, block: TransactionBuilder.() -> Any?): SignedTransaction {
return services.signInitialTransaction(
TransactionBuilder(notary).apply {
addCommand(dummyCommand(services.myInfo.singleIdentity().owningKey))

View File

@ -25,7 +25,6 @@ import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import org.junit.After
@ -43,8 +42,8 @@ class ScheduledFlowTests {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var bobNode: StartedNode
private lateinit var notary: Party
private lateinit var alice: Party
private lateinit var bob: Party

View File

@ -36,7 +36,6 @@ import net.corda.testing.internal.LogHelper
import net.corda.testing.node.InMemoryMessagingNetwork.MessageTransfer
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
import net.corda.testing.node.internal.*
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType
@ -57,8 +56,8 @@ class FlowFrameworkTests {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: TestStartedNode
private lateinit var alice: Party
private lateinit var bob: Party
private lateinit var notaryIdentity: Party
@ -446,7 +445,7 @@ class FlowFrameworkTests {
private val normalEnd = ExistingSessionMessage(SessionId(0), EndSessionMessage) // NormalSessionEnd(0)
private fun StartedNode<*>.sendSessionMessage(message: SessionMessage, destination: Party) {
private fun StartedNode.sendSessionMessage(message: SessionMessage, destination: Party) {
services.networkService.apply {
val address = getAddressOfParty(PartyInfo.SingleNode(destination, emptyList()))
send(createMessage(FlowMessagingImpl.sessionTopic, message.serialize().bytes), address)
@ -468,9 +467,9 @@ class FlowFrameworkTripartyTests {
}
private lateinit var mockNet: InternalMockNetwork
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var charlieNode: StartedNode<MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: TestStartedNode
private lateinit var charlieNode: TestStartedNode
private lateinit var alice: Party
private lateinit var bob: Party
private lateinit var charlie: Party
@ -619,7 +618,7 @@ class FlowFrameworkTripartyTests {
assertThat(receivedSessionMessages).containsExactly(*expected)
}
private fun assertSessionTransfers(node: StartedNode<MockNode>, vararg expected: SessionTransfer): List<SessionTransfer> {
private fun assertSessionTransfers(node: TestStartedNode, vararg expected: SessionTransfer): List<SessionTransfer> {
val actualForNode = receivedSessionMessages.filter { it.from == node.internals.id || it.to == node.network.myAddress }
assertThat(actualForNode).containsExactly(*expected)
return actualForNode
@ -636,8 +635,8 @@ class FlowFrameworkPersistenceTests {
private lateinit var mockNet: InternalMockNetwork
private val receivedSessionMessages = ArrayList<SessionTransfer>()
private lateinit var aliceNode: StartedNode<MockNode>
private lateinit var bobNode: StartedNode<MockNode>
private lateinit var aliceNode: TestStartedNode
private lateinit var bobNode: TestStartedNode
private lateinit var notaryIdentity: Party
private lateinit var alice: Party
private lateinit var bob: Party
@ -749,7 +748,7 @@ class FlowFrameworkPersistenceTests {
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//region Helpers
private inline fun <reified P : FlowLogic<*>> StartedNode<MockNode>.restartAndGetRestoredFlow(): P {
private inline fun <reified P : FlowLogic<*>> TestStartedNode.restartAndGetRestoredFlow(): P {
val newNode = mockNet.restartNode(this)
newNode.internals.acceptableLiveFiberCountOnStop = 1
mockNet.runNetwork()
@ -760,7 +759,7 @@ class FlowFrameworkPersistenceTests {
assertThat(receivedSessionMessages).containsExactly(*expected)
}
private fun assertSessionTransfers(node: StartedNode<MockNode>, vararg expected: SessionTransfer): List<SessionTransfer> {
private fun assertSessionTransfers(node: TestStartedNode, vararg expected: SessionTransfer): List<SessionTransfer> {
val actualForNode = receivedSessionMessages.filter { it.from == node.internals.id || it.to == node.network.myAddress }
assertThat(actualForNode).containsExactly(*expected)
return actualForNode
@ -775,7 +774,7 @@ class FlowFrameworkPersistenceTests {
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<*>> StartedNode.getSingleFlow(): Pair<P, CordaFuture<*>> {
return smm.findStateMachines(P::class.java).single()
}
@ -809,8 +808,8 @@ private fun Observable<MessageTransfer>.toSessionTransfers(): Observable<Session
private fun errorMessage(errorResponse: FlowException? = null) = ExistingSessionMessage(SessionId(0), ErrorSessionMessage(errorResponse, 0))
private infix fun StartedNode<MockNode>.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 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 data class SessionTransfer(val from: Int, val message: SessionMessage, val to: MessageRecipients) {
val isPayloadTransfer: Boolean get() =
@ -819,7 +818,7 @@ private data class SessionTransfer(val from: Int, val message: SessionMessage, v
override fun toString(): String = "$from sent $message to $to"
}
private inline fun <reified P : FlowLogic<*>> StartedNode<*>.registerFlowFactory(
private inline fun <reified P : FlowLogic<*>> TestStartedNode.registerFlowFactory(
initiatingFlowClass: KClass<out FlowLogic<*>>,
initiatedFlowVersion: Int = 1,
noinline flowFactory: (FlowSession) -> P): CordaFuture<P> {

View File

@ -27,8 +27,8 @@ import kotlin.test.assertEquals
class IdempotentFlowTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var nodeA: StartedNode<InternalMockNetwork.MockNode>
private lateinit var nodeB: StartedNode<InternalMockNetwork.MockNode>
private lateinit var nodeA: StartedNode
private lateinit var nodeB: StartedNode
companion object {
val executionCounter = AtomicInteger(0)

View File

@ -18,10 +18,10 @@ import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.nodeapi.internal.persistence.contextTransaction
import net.corda.testing.node.internal.cordappsForPackages
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
import net.corda.testing.node.internal.MessagingServiceSpy
import net.corda.testing.node.internal.newContext
import net.corda.testing.node.internal.setMessagingServiceSpy
import net.corda.testing.node.internal.*
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.hibernate.exception.ConstraintViolationException
@ -38,8 +38,8 @@ import kotlin.test.assertNull
class RetryFlowMockTest {
private lateinit var mockNet: InternalMockNetwork
private lateinit var nodeA: StartedNode<MockNode>
private lateinit var nodeB: StartedNode<MockNode>
private lateinit var nodeA: TestStartedNode
private lateinit var nodeB: TestStartedNode
@Before
fun start() {
@ -53,7 +53,7 @@ class RetryFlowMockTest {
KeepSendingFlow.count.set(0)
}
private fun <T> StartedNode<MockNode>.startFlow(logic: FlowLogic<T>): CordaFuture<T> {
private fun <T> StartedNode.startFlow(logic: FlowLogic<T>): CordaFuture<T> {
return this.services.startFlow(logic, this.services.newContext()).flatMap { it.resultFuture }
}

View File

@ -27,7 +27,7 @@ import kotlin.test.assertFailsWith
class NotaryServiceTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var notaryServices: ServiceHub
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: StartedNode
private lateinit var notary: Party
private lateinit var alice: Party
@ -55,7 +55,7 @@ class NotaryServiceTests {
internal companion object {
/** This is used by both [NotaryServiceTests] and [ValidatingNotaryServiceTests]. */
fun notariseWithTooManyInputs(node: StartedNode<InternalMockNetwork.MockNode>, party: Party, notary: Party, network: InternalMockNetwork) {
fun notariseWithTooManyInputs(node: StartedNode, party: Party, notary: Party, network: InternalMockNetwork) {
val stx = generateTransaction(node, party, notary)
val future = node.services.startFlow(DummyClientFlow(stx, notary)).resultFuture
@ -63,7 +63,7 @@ class NotaryServiceTests {
assertFailsWith<NotaryException> { future.getOrThrow() }
}
private fun generateTransaction(node: StartedNode<InternalMockNetwork.MockNode>, party: Party, notary: Party): SignedTransaction {
private fun generateTransaction(node: StartedNode, party: Party, notary: Party): SignedTransaction {
val txHash = SecureHash.randomSHA256()
val inputs = (1..10_005).map { StateRef(txHash, it) }
val tx = NotaryChangeTransactionBuilder(inputs, notary, party).build()

View File

@ -27,7 +27,6 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.internal.StartedNode
import net.corda.node.services.issueInvalidState
import net.corda.node.services.messaging.Message
import net.corda.node.services.statemachine.InitialSessionMessage
@ -43,6 +42,7 @@ import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.MessagingServiceSpy
import net.corda.testing.node.internal.setMessagingServiceSpy
import net.corda.testing.node.internal.startFlow
import net.corda.testing.node.internal.*
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
@ -56,8 +56,8 @@ import kotlin.test.assertTrue
class ValidatingNotaryServiceTests {
private lateinit var mockNet: InternalMockNetwork
private lateinit var notaryNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var aliceNode: StartedNode<InternalMockNetwork.MockNode>
private lateinit var notaryNode: TestStartedNode
private lateinit var aliceNode: TestStartedNode
private lateinit var notary: Party
private lateinit var alice: Party

View File

@ -4,8 +4,7 @@ import net.corda.core.flows.FlowLogic
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.NodeConfiguration
import net.corda.nodeapi.internal.persistence.CordaPersistence
@ -56,7 +55,7 @@ data class InProcessImpl(
override val useHTTPS: Boolean,
private val nodeThread: Thread,
private val onStopCallback: () -> Unit,
private val node: StartedNode<Node>
private val node: StartedNodeWithInternals
) : InProcess, NodeHandleInternal {
val database: CordaPersistence = node.database
override val services: StartedNodeServices get() = node.services

View File

@ -10,7 +10,6 @@ import net.corda.core.node.NetworkParameters
import net.corda.core.node.NodeInfo
import net.corda.core.node.ServiceHub
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.config.NodeConfiguration
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.DUMMY_NOTARY_NAME
@ -128,9 +127,9 @@ class UnstartedMockNode private constructor(private val node: InternalMockNetwor
}
/** A class that represents a started mock node for testing. */
class StartedMockNode private constructor(private val node: StartedNode<InternalMockNetwork.MockNode>) {
class StartedMockNode private constructor(private val node: TestStartedNode) {
companion object {
internal fun create(node: StartedNode<InternalMockNetwork.MockNode>): StartedMockNode {
internal fun create(node: TestStartedNode): StartedMockNode {
return StartedMockNode(node)
}
}

View File

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

View File

@ -8,10 +8,13 @@ import net.corda.core.DoNotImplement
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.random63BitValue
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.internal.*
import net.corda.core.internal.notary.NotaryService
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.MessageRecipients
import net.corda.core.messaging.RPCOps
import net.corda.core.messaging.SingleMessageRecipient
@ -24,18 +27,25 @@ import net.corda.core.utilities.*
import net.corda.node.VersionInfo
import net.corda.node.cordapp.CordappLoader
import net.corda.node.internal.AbstractNode
import net.corda.node.internal.InitiatedFlowFactory
import net.corda.node.internal.StartedNode
import net.corda.node.internal.cordapp.JarScanningCordappLoader
import net.corda.node.services.api.FlowStarter
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.*
import net.corda.node.services.keys.E2ETestKeyManagementService
import net.corda.node.services.keys.KeyManagementServiceInternal
import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.persistence.NodeAttachmentService
import net.corda.node.services.statemachine.StateMachineManager
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
import net.corda.node.services.transactions.BFTSMaRt
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.nodeapi.internal.DevIdentityGenerator
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.driver.TestCorDapp
@ -46,6 +56,7 @@ import net.corda.testing.node.*
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import org.apache.activemq.artemis.utils.ReusableLatch
import org.apache.sshd.common.util.security.SecurityUtils
import rx.Observable
import rx.Scheduler
import rx.internal.schedulers.CachedThreadScheduler
import java.math.BigInteger
@ -59,7 +70,7 @@ import java.util.concurrent.atomic.AtomicInteger
val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor")
fun StartedNode<InternalMockNetwork.MockNode>.pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? {
fun TestStartedNode.pumpReceive(block: Boolean = false): InMemoryMessagingNetwork.MessageTransfer? {
return (network as InternalMockMessagingService).pumpReceive(block)
}
@ -88,6 +99,18 @@ data class InternalMockNodeParameters(
)
}
/**
* A [StartedNode] which exposes its internal [InternalMockNetwork.MockNode] for testing.
*/
interface TestStartedNode : StartedNode {
val internals: InternalMockNetwork.MockNode
fun <F : FlowLogic<*>> internalRegisterFlowFactory(initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F>
}
open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParameters(),
val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped,
val threadPerNode: Boolean = defaultParameters.threadPerNode,
@ -136,13 +159,13 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
* Returns the list of nodes started by the network. Each notary specified when the network is constructed ([notarySpecs]
* parameter) maps 1:1 to the notaries returned by this list.
*/
val notaryNodes: List<StartedNode<MockNode>>
val notaryNodes: List<TestStartedNode>
/**
* Returns the single notary node on the network. Throws if there are none or more than one.
* @see notaryNodes
*/
val defaultNotaryNode: StartedNode<MockNode>
val defaultNotaryNode: TestStartedNode
get() {
return when (notaryNodes.size) {
0 -> throw IllegalStateException("There are no notaries defined on the network")
@ -213,7 +236,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
@VisibleForTesting
internal open fun createNotaries(): List<StartedNode<MockNode>> {
internal open fun createNotaries(): List<TestStartedNode> {
return notarySpecs.map { (name, validating) ->
createNode(InternalMockNodeParameters(legalName = name, configOverrides = {
doReturn(NotaryConfig(validating)).whenever(it).notary
@ -230,7 +253,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
}
open class MockNode(args: MockNodeArgs, cordappLoader: CordappLoader = JarScanningCordappLoader.fromDirectories(args.config.cordappDirectories)) : AbstractNode(
open class MockNode(args: MockNodeArgs, cordappLoader: CordappLoader = JarScanningCordappLoader.fromDirectories(args.config.cordappDirectories)) : AbstractNode<TestStartedNode>(
args.config,
TestClock(Clock.systemUTC()),
args.version,
@ -238,6 +261,45 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
args.network.getServerThread(args.id),
args.network.busyLatch
) {
/** The actual [StartedNode] implementation created by this node */
private class TestStartedNodeImpl(
override val internals: MockNode,
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?) : TestStartedNode {
override fun <F : FlowLogic<*>> internalRegisterFlowFactory(
initiatingFlowClass: Class<out FlowLogic<*>>,
flowFactory: InitiatedFlowFactory<F>,
initiatedFlowClass: Class<F>,
track: Boolean): Observable<F> =
internals.internalRegisterFlowFactory(smm, initiatingFlowClass, flowFactory, initiatedFlowClass, track)
override fun dispose() = internals.stop()
override fun <T : FlowLogic<*>> registerInitiatedFlow(initiatedFlowClass: Class<T>): Observable<T> =
internals.registerInitiatedFlow(smm, initiatedFlowClass)
}
override fun createStartedNode(nodeInfo: NodeInfo, rpcOps: CordaRPCOps, notaryService: NotaryService?): TestStartedNode =
TestStartedNodeImpl(
this,
attachments,
network,
object : StartedNodeServices, ServiceHubInternal by services, FlowStarter by flowStarter { },
nodeInfo,
smm,
database,
rpcOps,
notaryService
)
companion object {
private val staticLog = contextLogger()
}
@ -258,16 +320,14 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
}
override val started: StartedNode<MockNode>? get() = uncheckedCast(super.started)
override val started: TestStartedNode? get() = uncheckedCast(super.started)
override fun start(): StartedNode<MockNode> {
override fun start(): TestStartedNode {
mockNet.networkParametersCopier.install(configuration.baseDirectory)
val started: StartedNode<MockNode> = uncheckedCast(super.start())
advertiseNodeToNetwork(started)
return started
return super.start().also { advertiseNodeToNetwork(it) }
}
private fun advertiseNodeToNetwork(newNode: StartedNode<MockNode>) {
private fun advertiseNodeToNetwork(newNode: TestStartedNode) {
mockNet.nodes
.mapNotNull { it.started }
.forEach { existingNode ->
@ -364,20 +424,20 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
return createUnstartedNode(parameters, defaultFactory)
}
fun <N : MockNode> createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> N): N {
fun createUnstartedNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): MockNode {
return createNodeImpl(parameters, nodeFactory, false)
}
fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters()): StartedNode<MockNode> {
fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters()): TestStartedNode {
return createNode(parameters, defaultFactory)
}
/** Like the other [createNode] but takes a [nodeFactory] and propagates its [MockNode] subtype. */
fun <N : MockNode> createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> N): StartedNode<N> {
fun createNode(parameters: InternalMockNodeParameters = InternalMockNodeParameters(), nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): TestStartedNode {
return uncheckedCast(createNodeImpl(parameters, nodeFactory, true).started)!!
}
private fun <N : MockNode> createNodeImpl(parameters: InternalMockNodeParameters, nodeFactory: (MockNodeArgs, CordappLoader?) -> N, start: Boolean): N {
private fun createNodeImpl(parameters: InternalMockNodeParameters, nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode, start: Boolean): MockNode {
val id = parameters.forcedID ?: nextNodeId++
val config = mockNodeConfiguration().also {
doReturn(baseDirectory(id).createDirectories()).whenever(it).baseDirectory
@ -399,7 +459,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
return node
}
fun <N : MockNode> restartNode(node: StartedNode<N>, nodeFactory: (MockNodeArgs, CordappLoader?) -> N): StartedNode<N> {
fun restartNode(node: TestStartedNode, nodeFactory: (MockNodeArgs, CordappLoader?) -> MockNode): TestStartedNode {
node.internals.disableDBCloseOnStop()
node.dispose()
return createNode(
@ -408,7 +468,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
)
}
fun restartNode(node: StartedNode<MockNode>): StartedNode<MockNode> = restartNode(node, defaultFactory)
fun restartNode(node: TestStartedNode): TestStartedNode = restartNode(node, defaultFactory)
fun baseDirectory(nodeId: Int): Path = testDirectory / "nodes/$nodeId"
@ -434,7 +494,7 @@ open class InternalMockNetwork(defaultParameters: MockNetworkParameters = MockNe
}
@JvmOverloads
fun createPartyNode(legalName: CordaX500Name? = null): StartedNode<MockNode> {
fun createPartyNode(legalName: CordaX500Name? = null): TestStartedNode {
return createNode(InternalMockNodeParameters(legalName = legalName))
}
@ -475,7 +535,7 @@ open class MessagingServiceSpy(val messagingService: MessagingService) : Messagi
/**
* Attach a [MessagingServiceSpy] to the [InternalMockNetwork.MockNode] allowing interception and modification of messages.
*/
fun StartedNode<InternalMockNetwork.MockNode>.setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) {
fun TestStartedNode.setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) {
internals.setMessagingServiceSpy(messagingServiceSpy)
}
@ -499,4 +559,4 @@ private fun mockNodeConfiguration(): NodeConfiguration {
doReturn(5.seconds.toMillis()).whenever(it).additionalNodeInfoPollingFrequencyMsec
doReturn(null).whenever(it).devModeOptions
}
}
}

View File

@ -11,7 +11,8 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.loggerFor
import net.corda.node.VersionInfo
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.StartedNodeWithInternals
import net.corda.node.services.config.*
import net.corda.nodeapi.internal.config.toConfig
import net.corda.nodeapi.internal.network.NetworkParametersCopier
@ -46,7 +47,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
val tempFolder = TemporaryFolder()
private lateinit var defaultNetworkParameters: NetworkParametersCopier
private val nodes = mutableListOf<StartedNode<Node>>()
private val nodes = mutableListOf<StartedNodeWithInternals>()
private val nodeInfos = mutableListOf<NodeInfo>()
private val portAllocation = PortAllocation.Incremental(10000)
@ -86,7 +87,7 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
fun startNode(legalName: CordaX500Name,
platformVersion: Int = 1,
rpcUsers: List<User> = emptyList(),
configOverrides: Map<String, Any> = emptyMap()): StartedNode<Node> {
configOverrides: Map<String, Any> = emptyMap()): StartedNodeWithInternals {
val baseDirectory = baseDirectory(legalName).createDirectories()
val p2pAddress = configOverrides["p2pAddress"] ?: portAllocation.nextHostAndPort().toString()
val config = ConfigHelper.loadConfig(
@ -118,11 +119,12 @@ abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyLi
}
defaultNetworkParameters.install(baseDirectory)
val node = InProcessNode(parsedConfig, MOCK_VERSION_INFO.copy(platformVersion = platformVersion)).start()
val internals = InProcessNode(parsedConfig, MOCK_VERSION_INFO.copy(platformVersion = platformVersion))
val node = internals.start() as StartedNodeWithInternals
nodes += node
ensureAllNetworkMapCachesHaveAllNodeInfos()
thread(name = legalName.organisation) {
node.internals.run()
internals.run()
}
return node