Merge remote-tracking branch 'open/master' into colljos-os-merge-rc01

This commit is contained in:
josecoll
2017-12-18 10:24:38 +00:00
215 changed files with 4624 additions and 1717 deletions

View File

@ -288,11 +288,13 @@ class FlowStackSnapshotTest {
@Test
fun `flowStackSnapshot object is serializable`() {
val mockNet = MockNetwork(threadPerNode = true)
val mockNet = MockNetwork(emptyList(), threadPerNode = true)
val node = mockNet.createPartyNode()
node.registerInitiatedFlow(DummyFlow::class.java)
node.services.startFlow(FlowStackSnapshotSerializationTestingFlow()).resultFuture.get()
val thrown = try {
// Due to the [MockNetwork] implementation, the easiest way to trigger object serialization process is at
// the network stopping stage.
mockNet.stopNodes()
null
} catch (exception: Exception) {

View File

@ -45,8 +45,8 @@ import kotlin.concurrent.thread
* a service is addressed.
*/
@ThreadSafe
class InMemoryMessagingNetwork(
val sendManuallyPumped: Boolean,
class InMemoryMessagingNetwork internal constructor(
private val sendManuallyPumped: Boolean,
private val servicePeerAllocationStrategy: ServicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random(),
private val messagesInFlight: ReusableLatch = ReusableLatch()
) : SingletonSerializeAsToken() {
@ -94,7 +94,7 @@ class InMemoryMessagingNetwork(
/**
* Creates a node at the given address: useful if you want to recreate a node to simulate a restart.
*
* @param manuallyPumped if set to true, then you are expected to call the [InMemoryMessaging.pump] method on the [InMemoryMessaging]
* @param manuallyPumped if set to true, then you are expected to call [InMemoryMessaging.pumpReceive]
* in order to cause the delivery of a single message, which will occur on the thread of the caller. If set to false
* then this class will set up a background thread to deliver messages asynchronously, if the handler specifies no
* executor.
@ -153,9 +153,6 @@ class InMemoryMessagingNetwork(
}
}
val everyoneOnline: AllPossibleRecipients = object : AllPossibleRecipients {}
fun stop() {
val nodes = synchronized(this) {
counter = -1
@ -226,7 +223,7 @@ class InMemoryMessagingNetwork(
return transfer
}
fun pumpSendInternal(transfer: MessageTransfer) {
private fun pumpSendInternal(transfer: MessageTransfer) {
when (transfer.recipients) {
is PeerHandle -> getQueueForPeerHandle(transfer.recipients).add(transfer)
is ServiceHandle -> {
@ -271,7 +268,8 @@ class InMemoryMessagingNetwork(
private val peerHandle: PeerHandle,
private val executor: AffinityExecutor,
private val database: CordaPersistence) : SingletonSerializeAsToken(), MessagingService {
inner class Handler(val topicSession: String, val callback: MessageHandler) : MessageHandlerRegistration
privateinner class Handler(val topicSession: String,
val callback: MessageHandler) : MessageHandlerRegistration
@Volatile
private var running = true

View File

@ -1,39 +0,0 @@
package net.corda.testing.node
import net.corda.core.concurrent.CordaFuture
import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.concurrent.doneFuture
import net.corda.core.node.NodeInfo
import net.corda.core.node.services.NetworkMapCache
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.network.PersistentNetworkMapCache
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.testing.getTestPartyAndCertificate
import rx.Observable
import rx.subjects.PublishSubject
import java.math.BigInteger
/**
* Network map cache with no backing map service.
*/
class MockNetworkMapCache(database: CordaPersistence) : PersistentNetworkMapCache(database, emptyList()) {
private companion object {
val BANK_C = getTestPartyAndCertificate(CordaX500Name(organisation = "Bank C", locality = "London", country = "GB"), entropyToKeyPair(BigInteger.valueOf(1000)).public)
val BANK_D = getTestPartyAndCertificate(CordaX500Name(organisation = "Bank D", locality = "London", country = "GB"), entropyToKeyPair(BigInteger.valueOf(2000)).public)
val BANK_C_ADDR = NetworkHostAndPort("bankC", 8080)
val BANK_D_ADDR = NetworkHostAndPort("bankD", 8080)
}
override val changed: Observable<NetworkMapCache.MapChange> = PublishSubject.create<NetworkMapCache.MapChange>()
override val nodeReady: CordaFuture<Void?> get() = doneFuture(null)
init {
val mockNodeA = NodeInfo(listOf(BANK_C_ADDR), listOf(BANK_C), 1, serial = 1L)
val mockNodeB = NodeInfo(listOf(BANK_D_ADDR), listOf(BANK_D), 1, serial = 1L)
addNode(mockNodeA)
addNode(mockNodeB)
}
}

View File

@ -22,14 +22,14 @@ import net.corda.core.node.services.KeyManagementService
import net.corda.core.serialization.SerializationWhitelist
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.seconds
import net.corda.node.VersionInfo
import net.corda.node.internal.AbstractNode
import net.corda.node.internal.StartedNode
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.BFTSMaRtConfiguration
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.NotaryConfig
import net.corda.node.services.api.IdentityServiceInternal
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.*
import net.corda.node.services.keys.E2ETestKeyManagementService
import net.corda.node.services.messaging.MessagingService
import net.corda.node.services.transactions.BFTNonValidatingNotaryService
@ -37,12 +37,15 @@ import net.corda.node.services.transactions.BFTSMaRt
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
import net.corda.node.utilities.AffinityExecutor
import net.corda.node.utilities.AffinityExecutor.ServiceAffinityExecutor
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.NotaryInfo
import net.corda.nodeapi.internal.NetworkParametersCopier
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NotaryInfo
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.DUMMY_NOTARY_NAME
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.internal.rigorousMock
import net.corda.testing.internal.testThreadFactory
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
@ -71,13 +74,13 @@ data class MockNetworkParameters(
val servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = InMemoryMessagingNetwork.ServicePeerAllocationStrategy.Random(),
val defaultFactory: (MockNodeArgs) -> MockNetwork.MockNode = MockNetwork::MockNode,
val initialiseSerialization: Boolean = true,
val cordappPackages: List<String> = emptyList()) {
val notarySpecs: List<MockNetwork.NotarySpec> = listOf(MockNetwork.NotarySpec(DUMMY_NOTARY_NAME))) {
fun setNetworkSendManuallyPumped(networkSendManuallyPumped: Boolean) = copy(networkSendManuallyPumped = networkSendManuallyPumped)
fun setThreadPerNode(threadPerNode: Boolean) = copy(threadPerNode = threadPerNode)
fun setServicePeerAllocationStrategy(servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy) = copy(servicePeerAllocationStrategy = servicePeerAllocationStrategy)
fun setDefaultFactory(defaultFactory: (MockNodeArgs) -> MockNetwork.MockNode) = copy(defaultFactory = defaultFactory)
fun setInitialiseSerialization(initialiseSerialization: Boolean) = copy(initialiseSerialization = initialiseSerialization)
fun setCordappPackages(cordappPackages: List<String>) = copy(cordappPackages = cordappPackages)
fun setNotarySpecs(notarySpecs: List<MockNetwork.NotarySpec>) = copy(notarySpecs = notarySpecs)
}
/**
@ -90,7 +93,8 @@ data class MockNodeParameters(
val forcedID: Int? = null,
val legalName: CordaX500Name? = null,
val entropyRoot: BigInteger = BigInteger.valueOf(random63BitValue()),
val configOverrides: (NodeConfiguration) -> Any? = {}) {
val configOverrides: (NodeConfiguration) -> Any? = {},
val version: VersionInfo = MOCK_VERSION_INFO) {
fun setForcedID(forcedID: Int?) = copy(forcedID = forcedID)
fun setLegalName(legalName: CordaX500Name?) = copy(legalName = legalName)
fun setEntropyRoot(entropyRoot: BigInteger) = copy(entropyRoot = entropyRoot)
@ -101,7 +105,8 @@ data class MockNodeArgs(
val config: NodeConfiguration,
val network: MockNetwork,
val id: Int,
val entropyRoot: BigInteger
val entropyRoot: BigInteger,
val version: VersionInfo = MOCK_VERSION_INFO
)
/**
@ -120,16 +125,17 @@ data class MockNodeArgs(
* By default a single notary node is automatically started, which forms part of the network parameters for all the nodes.
* This node is available by calling [defaultNotaryNode].
*/
class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParameters(),
class MockNetwork(private val cordappPackages: List<String>,
defaultParameters: MockNetworkParameters = MockNetworkParameters(),
private val networkSendManuallyPumped: Boolean = defaultParameters.networkSendManuallyPumped,
private val threadPerNode: Boolean = defaultParameters.threadPerNode,
servicePeerAllocationStrategy: InMemoryMessagingNetwork.ServicePeerAllocationStrategy = defaultParameters.servicePeerAllocationStrategy,
private val defaultFactory: (MockNodeArgs) -> MockNode = defaultParameters.defaultFactory,
initialiseSerialization: Boolean = defaultParameters.initialiseSerialization,
private val notarySpecs: List<NotarySpec> = listOf(NotarySpec(DUMMY_NOTARY_NAME)),
private val cordappPackages: List<String> = defaultParameters.cordappPackages) {
private val notarySpecs: List<NotarySpec> = defaultParameters.notarySpecs) {
/** Helper constructor for creating a [MockNetwork] with custom parameters from Java. */
constructor(parameters: MockNetworkParameters) : this(defaultParameters = parameters)
@JvmOverloads
constructor(cordappPackages: List<String>, parameters: MockNetworkParameters = MockNetworkParameters()) : this(cordappPackages, defaultParameters = parameters)
init {
// Apache SSHD for whatever reason registers a SFTP FileSystemProvider - which gets loaded by JimFS.
@ -147,9 +153,13 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
private val networkId = random63BitValue()
private val networkParameters: NetworkParametersCopier
private val _nodes = mutableListOf<MockNode>()
private val serializationEnv = setGlobalSerialization(initialiseSerialization)
private val serializationEnv = try {
setGlobalSerialization(initialiseSerialization)
} catch (e: IllegalStateException) {
throw IllegalStateException("Using more than one MockNetwork simultaneously is not supported.", e)
}
private val sharedUserCount = AtomicInteger(0)
/** A read only view of the current set of executing nodes. */
/** A read only view of the current set of nodes. */
val nodes: List<MockNode> get() = _nodes
/**
@ -220,12 +230,12 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
}
private fun generateNotaryIdentities(): List<NotaryInfo> {
return notarySpecs.mapIndexed { index, spec ->
return notarySpecs.mapIndexed { index, (name, validating) ->
val identity = ServiceIdentityGenerator.generateToDisk(
dirs = listOf(baseDirectory(nextNodeId + index)),
serviceName = spec.name,
serviceName = name,
serviceId = "identity")
NotaryInfo(identity, spec.validating)
NotaryInfo(identity, validating)
}
}
@ -240,7 +250,7 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
open class MockNode(args: MockNodeArgs) : AbstractNode(
args.config,
TestClock(Clock.systemUTC()),
MOCK_VERSION_INFO,
args.version,
CordappLoader.createDefaultWithTestPackages(args.config, args.network.cordappPackages),
args.network.busyLatch
) {
@ -385,14 +395,14 @@ class MockNetwork(defaultParameters: MockNetworkParameters = MockNetworkParamete
private fun <N : MockNode> createNodeImpl(parameters: MockNodeParameters, nodeFactory: (MockNodeArgs) -> N, start: Boolean): N {
val id = parameters.forcedID ?: nextNodeId++
val config = testNodeConfiguration(
baseDirectory = baseDirectory(id).createDirectories(),
myLegalName = parameters.legalName ?: CordaX500Name(organisation = "Mock Company $id", locality = "London", country = "GB")).also {
val config = mockNodeConfiguration().also {
doReturn(baseDirectory(id).createDirectories()).whenever(it).baseDirectory
doReturn(parameters.legalName ?: CordaX500Name("Mock Company $id", "London", "GB")).whenever(it).myLegalName
doReturn(makeTestDataSourceProperties("node_$id", "net_$networkId")).whenever(it).dataSourceProperties
doReturn(makeTestDatabaseProperties("node_$id")).whenever(it).database
parameters.configOverrides(it)
}
val node = nodeFactory(MockNodeArgs(config, this, id, parameters.entropyRoot))
val node = nodeFactory(MockNodeArgs(config, this, id, parameters.entropyRoot, parameters.version))
_nodes += node
if (start) {
node.start()
@ -474,3 +484,24 @@ open class MessagingServiceSpy(val messagingService: MessagingService) : Messagi
fun StartedNode<MockNetwork.MockNode>.setMessagingServiceSpy(messagingServiceSpy: MessagingServiceSpy) {
internals.setMessagingServiceSpy(messagingServiceSpy)
}
private fun mockNodeConfiguration(): NodeConfiguration {
abstract class AbstractNodeConfiguration : NodeConfiguration
return rigorousMock<AbstractNodeConfiguration>().also {
doReturn("cordacadevpass").whenever(it).keyStorePassword
doReturn("trustpass").whenever(it).trustStorePassword
doReturn(emptyList<User>()).whenever(it).rpcUsers
doReturn(null).whenever(it).notary
doReturn(DatabaseConfig()).whenever(it).database
doReturn("").whenever(it).emailAddress
doReturn("").whenever(it).exportJMXto
doReturn(true).whenever(it).devMode
doReturn(null).whenever(it).compatibilityZoneURL
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
doReturn(VerifierType.InMemory).whenever(it).verifierType
doReturn(5).whenever(it).messageRedeliveryDelaySeconds
doReturn(5.seconds.toMillis()).whenever(it).additionalNodeInfoPollingFrequencyMsec
doReturn(null).whenever(it).devModeOptions
doReturn(true).whenever(it).useAMQPBridges
}
}

View File

@ -59,7 +59,7 @@ import java.sql.Connection
import java.time.Clock
import java.util.*
fun makeTestIdentityService(identities: Iterable<PartyAndCertificate> = emptySet()) = InMemoryIdentityService(identities, DEV_TRUST_ROOT)
fun makeTestIdentityService(vararg identities: PartyAndCertificate) = InMemoryIdentityService(identities, DEV_TRUST_ROOT)
/**
* A singleton utility that only provides a mock identity, key and storage service. However, this is sufficient for
* building chains of transactions and verifying them. It isn't sufficient for testing flows however.
@ -68,8 +68,8 @@ open class MockServices private constructor(
cordappLoader: CordappLoader,
override val validatedTransactions: WritableTransactionStorage,
override val identityService: IdentityServiceInternal,
private val initialIdentityName: CordaX500Name,
val keys: Array<out KeyPair>
private val initialIdentity: TestIdentity,
private val moreKeys: Array<out KeyPair>
) : ServiceHub, StateLoader by validatedTransactions {
companion object {
@JvmStatic
@ -144,22 +144,22 @@ open class MockServices private constructor(
/**
* Makes database and mock services appropriate for unit tests.
* @param keys a list of [KeyPair] instances to be used by [MockServices].
* @param moreKeys a list of additional [KeyPair] instances to be used by [MockServices].
* @param identityService an instance of [IdentityServiceInternal], see [makeTestIdentityService].
* @param initialIdentityName the name of the first (typically sole) identity the services will represent.
* @param initialIdentity the first (typically sole) identity the services will represent.
* @return a pair where the first element is the instance of [CordaPersistence] and the second is [MockServices].
*/
@JvmStatic
fun makeTestDatabaseAndMockServices(keys: List<KeyPair>,
fun makeTestDatabaseAndMockServices(cordappPackages: List<String>,
identityService: IdentityServiceInternal,
cordappPackages: List<String> = emptyList(),
initialIdentityName: CordaX500Name): Pair<CordaPersistence, MockServices> {
initialIdentity: TestIdentity,
vararg moreKeys: KeyPair): Pair<CordaPersistence, MockServices> {
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
val dataSourceProps = makeTestDataSourceProperties(initialIdentityName.organisation)
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
val database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(initialIdentityName.organisation), identityService, schemaService)
val mockService = database.transaction {
object : MockServices(cordappLoader, identityService, initialIdentityName, keys.toTypedArray()) {
object : MockServices(cordappLoader, identityService, initialIdentity, moreKeys) {
override val vaultService: VaultServiceInternal = makeVaultService(database.hibernateConfig, schemaService)
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
@ -175,13 +175,18 @@ open class MockServices private constructor(
}
}
private constructor(cordappLoader: CordappLoader, identityService: IdentityServiceInternal, initialIdentityName: CordaX500Name, keys: Array<out KeyPair>) : this(cordappLoader, MockTransactionStorage(), identityService, initialIdentityName, keys)
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal, initialIdentityName: CordaX500Name, vararg keys: KeyPair) : this(CordappLoader.createWithTestPackages(cordappPackages), identityService, initialIdentityName, keys)
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal, initialIdentity: TestIdentity, vararg moreKeys: KeyPair) : this(CordappLoader.createWithTestPackages(cordappPackages), identityService, initialIdentity.name, arrayOf(initialIdentity.key) + moreKeys)
constructor(identityService: IdentityServiceInternal, initialIdentityName: CordaX500Name, vararg keys: KeyPair) : this(emptyList(), identityService, initialIdentityName, *keys)
constructor(identityService: IdentityServiceInternal, initialIdentityName: CordaX500Name) : this(identityService, initialIdentityName, generateKeyPair())
private constructor(cordappLoader: CordappLoader, identityService: IdentityServiceInternal, initialIdentity: TestIdentity, moreKeys: Array<out KeyPair>) : this(cordappLoader, MockTransactionStorage(), identityService, initialIdentity, moreKeys)
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentity: TestIdentity, vararg moreKeys: KeyPair) : this(CordappLoader.createWithTestPackages(cordappPackages), identityService, initialIdentity, moreKeys)
val key: KeyPair get() = keys.first()
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentityName: CordaX500Name, key: KeyPair, vararg moreKeys: KeyPair) : this(cordappPackages, identityService, TestIdentity(initialIdentityName, key), *moreKeys)
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), initialIdentityName: CordaX500Name) : this(cordappPackages, identityService, TestIdentity(initialIdentityName))
@JvmOverloads
constructor(cordappPackages: List<String>, identityService: IdentityServiceInternal = makeTestIdentityService(), vararg moreKeys: KeyPair) : this(cordappPackages, identityService, TestIdentity.fresh("MockServices"), *moreKeys)
override fun recordTransactions(statesToRecord: StatesToRecord, txs: Iterable<SignedTransaction>) {
txs.forEach {
@ -190,16 +195,14 @@ open class MockServices private constructor(
}
final override val attachments = MockAttachmentStorage()
override val keyManagementService: KeyManagementService by lazy { MockKeyManagementService(identityService, *keys) }
override val keyManagementService: KeyManagementService by lazy { MockKeyManagementService(identityService, *arrayOf(initialIdentity.keyPair) + moreKeys) }
override val vaultService: VaultService get() = throw UnsupportedOperationException()
override val contractUpgradeService: ContractUpgradeService get() = throw UnsupportedOperationException()
override val networkMapCache: NetworkMapCache get() = throw UnsupportedOperationException()
override val clock: Clock get() = Clock.systemUTC()
override val myInfo: NodeInfo
get() {
val identity = getTestPartyAndCertificate(initialIdentityName, key.public)
return NodeInfo(emptyList(), listOf(identity), 1, serial = 1L)
return NodeInfo(emptyList(), listOf(initialIdentity.identity), 1, serial = 1L)
}
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(2)
val mockCordappProvider = MockCordappProvider(cordappLoader, attachments)

View File

@ -2,8 +2,6 @@
package net.corda.testing.node
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.context.Actor
import net.corda.core.context.AuthServiceId
import net.corda.core.context.InvocationContext
@ -13,26 +11,34 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.internal.FlowStateMachine
import net.corda.core.node.ServiceHub
import net.corda.core.serialization.internal.effectiveSerializationEnv
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.*
import net.corda.nodeapi.internal.config.User
import net.corda.testing.*
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.makeTestIdentityService
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import java.nio.file.Path
import net.corda.testing.dsl.*
/**
* Creates and tests a ledger built by the passed in dsl.
*/
@JvmOverloads
fun ServiceHub.ledger(
notary: Party,
dsl: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.() -> Unit
notary: Party = TestIdentity.fresh("ledger notary").party,
script: LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter>.() -> Unit
): LedgerDSL<TestTransactionDSLInterpreter, TestLedgerDSLInterpreter> {
return LedgerDSL(TestLedgerDSLInterpreter(this), notary).apply(dsl)
val serializationExists = try {
effectiveSerializationEnv
true
} catch (e: IllegalStateException) {
false
}
return LedgerDSL(TestLedgerDSLInterpreter(this), notary).apply {
if (serializationExists) {
script()
} else {
SerializationEnvironmentRule.run("ledger") { script() }
}
}
}
/**
@ -40,37 +46,12 @@ fun ServiceHub.ledger(
*
* @see LedgerDSLInterpreter._transaction
*/
@JvmOverloads
fun ServiceHub.transaction(
notary: Party,
dsl: TransactionDSL<TransactionDSLInterpreter>.() -> EnforceVerifyOrFail
notary: Party = TestIdentity.fresh("transaction notary").party,
script: TransactionDSL<TransactionDSLInterpreter>.() -> EnforceVerifyOrFail
) = ledger(notary) {
dsl(TransactionDSL(TestTransactionDSLInterpreter(interpreter, TransactionBuilder(notary)), notary))
}
fun testNodeConfiguration(
baseDirectory: Path,
myLegalName: CordaX500Name): NodeConfiguration {
abstract class MockableNodeConfiguration : NodeConfiguration // Otherwise Mockito is defeated by val getters.
return rigorousMock<MockableNodeConfiguration>().also {
doReturn(baseDirectory).whenever(it).baseDirectory
doReturn(myLegalName).whenever(it).myLegalName
doReturn("cordacadevpass").whenever(it).keyStorePassword
doReturn("trustpass").whenever(it).trustStorePassword
doReturn(emptyList<User>()).whenever(it).rpcUsers
doReturn(null).whenever(it).notary
doReturn(makeTestDataSourceProperties(myLegalName.organisation)).whenever(it).dataSourceProperties
doReturn(makeTestDatabaseProperties(myLegalName.organisation)).whenever(it).database
doReturn("").whenever(it).emailAddress
doReturn("").whenever(it).exportJMXto
doReturn(true).whenever(it).devMode
doReturn(null).whenever(it).compatibilityZoneURL
doReturn(emptyList<CertChainPolicyConfig>()).whenever(it).certificateChainCheckPolicies
doReturn(VerifierType.InMemory).whenever(it).verifierType
doReturn(5).whenever(it).messageRedeliveryDelaySeconds
doReturn(5.seconds.toMillis()).whenever(it).additionalNodeInfoPollingFrequencyMsec
doReturn(null).whenever(it).devModeOptions
doReturn(EnterpriseConfiguration(MutualExclusionConfiguration(false, "", 20000, 40000))).whenever(it).enterpriseConfiguration //Enterprise only
}
TransactionDSL(TestTransactionDSLInterpreter(interpreter, TransactionBuilder(notary)), notary).script()
}
fun testActor(owningLegalIdentity: CordaX500Name = CordaX500Name("Test Company Inc.", "London", "GB")) = Actor(Actor.Id("Only For Testing"), AuthServiceId("TEST"), owningLegalIdentity)

View File

@ -10,6 +10,7 @@ import net.corda.cordform.CordformContext
import net.corda.cordform.CordformNode
import net.corda.core.concurrent.CordaFuture
import net.corda.core.concurrent.firstOf
import net.corda.core.crypto.random63BitValue
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.ThreadBox
import net.corda.core.internal.concurrent.*
@ -34,7 +35,8 @@ import net.corda.node.services.transactions.RaftNonValidatingNotaryService
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.utilities.registration.HTTPNetworkRegistrationService
import net.corda.node.utilities.registration.NetworkRegistrationHelper
import net.corda.nodeapi.internal.*
import net.corda.nodeapi.internal.ServiceIdentityGenerator
import net.corda.nodeapi.internal.addShutdownHook
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.config.parseAs
import net.corda.nodeapi.internal.config.toConfig
@ -42,8 +44,13 @@ import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.crypto.addOrReplaceCertificate
import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
import net.corda.nodeapi.internal.crypto.save
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NodeInfoFilesCopier
import net.corda.nodeapi.internal.network.NotaryInfo
import net.corda.testing.ALICE_NAME
import net.corda.testing.BOB_NAME
import net.corda.testing.DUMMY_BANK_A_NAME
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.*
import net.corda.testing.driver.*
import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
@ -244,6 +251,7 @@ class DriverDSLImpl(
}
internal fun startCordformNodes(cordforms: List<CordformNode>): CordaFuture<*> {
check(compatibilityZone == null) { "Cordform nodes should be run without compatibilityZone configuration" }
val clusterNodes = HashMultimap.create<ClusterType, CordaX500Name>()
val notaryInfos = ArrayList<NotaryInfo>()
@ -353,7 +361,7 @@ class DriverDSLImpl(
}
val notaryInfos = generateNotaryIdentities()
// The network parameters must be serialised before starting any of the nodes
networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos))
if (compatibilityZone == null) networkParameters = NetworkParametersCopier(testNetworkParameters(notaryInfos))
val nodeHandles = startNotaries()
_notaries = notaryInfos.zip(nodeHandles) { (identity, validating), nodes -> NotaryHandle(identity, validating, nodes) }
}
@ -514,7 +522,7 @@ class DriverDSLImpl(
val configuration = config.parseAsNodeConfiguration()
val baseDirectory = configuration.baseDirectory.createDirectories()
nodeInfoFilesCopier?.addConfig(baseDirectory)
networkParameters!!.install(baseDirectory)
networkParameters?.install(baseDirectory)
val onNodeExit: () -> Unit = {
nodeInfoFilesCopier?.removeConfig(baseDirectory)
countObservables.remove(configuration.myLegalName)
@ -889,7 +897,8 @@ fun <A> internalDriver(
}
fun getTimestampAsDirectoryName(): String {
return DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneOffset.UTC).format(Instant.now())
// Add a random number in case 2 tests are started in the same instant.
return DateTimeFormatter.ofPattern("yyyyMMddHHmmss").withZone(ZoneOffset.UTC).format(Instant.now()) + random63BitValue()
}
fun writeConfig(path: Path, filename: String, config: Config) {

View File

@ -12,10 +12,10 @@ import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.config.*
import net.corda.nodeapi.internal.NetworkParametersCopier
import net.corda.nodeapi.internal.config.User
import net.corda.testing.IntegrationTest
import net.corda.testing.SerializationEnvironmentRule
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.getFreeLocalPorts
import net.corda.testing.internal.testThreadFactory

View File

@ -17,7 +17,6 @@ import net.corda.core.internal.uncheckedCast
import net.corda.core.messaging.RPCOps
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.security.RPCSecurityManagerImpl
import net.corda.node.services.messaging.ArtemisMessagingServer
import net.corda.node.services.messaging.RPCServer
import net.corda.node.services.messaging.RPCServerConfiguration
import net.corda.nodeapi.ArtemisTcpTransport
@ -25,6 +24,7 @@ import net.corda.nodeapi.ConnectionDirection
import net.corda.nodeapi.RPCApi
import net.corda.nodeapi.internal.config.User
import net.corda.nodeapi.internal.serialization.KRYO_RPC_CLIENT_CONTEXT
import net.corda.testing.MAX_MESSAGE_SIZE
import net.corda.testing.driver.JmxPolicy
import net.corda.testing.driver.PortAllocation
import net.corda.testing.node.NotarySpec
@ -46,7 +46,7 @@ import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ
import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl
import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy
import org.apache.activemq.artemis.core.settings.impl.AddressSettings
import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection
import org.apache.activemq.artemis.spi.core.remoting.Connection
import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager3
import java.lang.reflect.Method
import java.nio.file.Path
@ -133,11 +133,11 @@ fun <A> rpcDriver(
private class SingleUserSecurityManager(val rpcUser: User) : ActiveMQSecurityManager3 {
override fun validateUser(user: String?, password: String?) = isValid(user, password)
override fun validateUserAndRole(user: String?, password: String?, roles: MutableSet<Role>?, checkType: CheckType?) = isValid(user, password)
override fun validateUser(user: String?, password: String?, remotingConnection: RemotingConnection?): String? {
override fun validateUser(user: String?, password: String?, connection: Connection?): String? {
return validate(user, password)
}
override fun validateUserAndRole(user: String?, password: String?, roles: MutableSet<Role>?, checkType: CheckType?, address: String?, connection: RemotingConnection?): String? {
override fun validateUserAndRole(user: String?, password: String?, roles: MutableSet<Role>?, checkType: CheckType?, address: String?, connection: Connection?): String? {
return validate(user, password)
}
@ -226,8 +226,8 @@ data class RPCDriverDSL(
fun <I : RPCOps> startInVmRpcServer(
rpcUser: User = rpcTestUser,
nodeLegalName: CordaX500Name = fakeNodeLegalName,
maxFileSize: Int = ArtemisMessagingServer.MAX_FILE_SIZE,
maxBufferedBytesPerClient: Long = 10L * ArtemisMessagingServer.MAX_FILE_SIZE,
maxFileSize: Int = MAX_MESSAGE_SIZE,
maxBufferedBytesPerClient: Long = 10L * MAX_MESSAGE_SIZE,
configuration: RPCServerConfiguration = RPCServerConfiguration.default,
ops: I
): CordaFuture<RpcServerHandle> {
@ -294,8 +294,8 @@ data class RPCDriverDSL(
serverName: String = "driver-rpc-server-${random63BitValue()}",
rpcUser: User = rpcTestUser,
nodeLegalName: CordaX500Name = fakeNodeLegalName,
maxFileSize: Int = ArtemisMessagingServer.MAX_FILE_SIZE,
maxBufferedBytesPerClient: Long = 10L * ArtemisMessagingServer.MAX_FILE_SIZE,
maxFileSize: Int = MAX_MESSAGE_SIZE,
maxBufferedBytesPerClient: Long = 10L * MAX_MESSAGE_SIZE,
configuration: RPCServerConfiguration = RPCServerConfiguration.default,
customPort: NetworkHostAndPort? = null,
ops: I
@ -377,8 +377,8 @@ data class RPCDriverDSL(
fun startRpcBroker(
serverName: String = "driver-rpc-server-${random63BitValue()}",
rpcUser: User = rpcTestUser,
maxFileSize: Int = ArtemisMessagingServer.MAX_FILE_SIZE,
maxBufferedBytesPerClient: Long = 10L * ArtemisMessagingServer.MAX_FILE_SIZE,
maxFileSize: Int = MAX_MESSAGE_SIZE,
maxBufferedBytesPerClient: Long = 10L * MAX_MESSAGE_SIZE,
customPort: NetworkHostAndPort? = null
): CordaFuture<RpcBrokerHandle> {
val hostAndPort = customPort ?: driverDSL.portAllocation.nextHostAndPort()
@ -401,8 +401,8 @@ data class RPCDriverDSL(
fun startInVmRpcBroker(
rpcUser: User = rpcTestUser,
maxFileSize: Int = ArtemisMessagingServer.MAX_FILE_SIZE,
maxBufferedBytesPerClient: Long = 10L * ArtemisMessagingServer.MAX_FILE_SIZE
maxFileSize: Int = MAX_MESSAGE_SIZE,
maxBufferedBytesPerClient: Long = 10L * MAX_MESSAGE_SIZE
): CordaFuture<RpcBrokerHandle> {
return driverDSL.executorService.fork {
val artemisConfig = createInVmRpcServerArtemisConfig(maxFileSize, maxBufferedBytesPerClient)
@ -430,7 +430,7 @@ data class RPCDriverDSL(
brokerHandle: RpcBrokerHandle
): RpcServerHandle {
val locator = ActiveMQClient.createServerLocatorWithoutHA(brokerHandle.clientTransportConfiguration).apply {
minLargeMessageSize = ArtemisMessagingServer.MAX_FILE_SIZE
minLargeMessageSize = MAX_MESSAGE_SIZE
isUseGlobalPools = false
}
val rpcSecurityManager = RPCSecurityManagerImpl.fromUserList(users = listOf(rpcUser), id = AuthServiceId("TEST_SECURITY_MANAGER"))

View File

@ -1,20 +1,17 @@
package net.corda.testing.node.network
package net.corda.testing.node.internal.network
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignedData
import net.corda.core.crypto.sha256
import net.corda.core.crypto.*
import net.corda.core.internal.cert
import net.corda.core.internal.toX509CertHolder
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.deserialize
import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.hours
import net.corda.nodeapi.internal.DigitalSignatureWithCert
import net.corda.nodeapi.internal.NetworkMap
import net.corda.nodeapi.internal.NetworkParameters
import net.corda.nodeapi.internal.SignedNetworkMap
import net.corda.nodeapi.internal.network.DigitalSignatureWithCert
import net.corda.nodeapi.internal.network.NetworkMap
import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.nodeapi.internal.network.SignedNetworkMap
import net.corda.nodeapi.internal.*
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509Utilities
@ -39,9 +36,11 @@ import javax.ws.rs.core.Response.ok
class NetworkMapServer(cacheTimeout: Duration,
hostAndPort: NetworkHostAndPort,
root_ca: CertificateAndKeyPair = ROOT_CA, // Default to ROOT_CA for testing.
vararg additionalServices: Any) : Closeable {
companion object {
val stubNetworkParameter = NetworkParameters(1, emptyList(), 1.hours, 10, 10, Instant.now(), 10)
val stubNetworkParameter = NetworkParameters(1, emptyList(), 10485760, 40000, Instant.now(), 10)
private val serializedParameters = stubNetworkParameter.serialize()
private fun networkMapKeyAndCert(rootCAKeyAndCert: CertificateAndKeyPair): CertificateAndKeyPair {
val networkMapKey = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
@ -56,9 +55,7 @@ class NetworkMapServer(cacheTimeout: Duration,
}
private val server: Server
// Default to ROOT_CA for testing.
// TODO: make this configurable?
private val service = InMemoryNetworkMapService(cacheTimeout, networkMapKeyAndCert(ROOT_CA))
private val service = InMemoryNetworkMapService(cacheTimeout, networkMapKeyAndCert(root_ca))
init {
server = Server(InetSocketAddress(hostAndPort.host, hostAndPort.port)).apply {
@ -99,13 +96,18 @@ class NetworkMapServer(cacheTimeout: Duration,
@Path("network-map")
class InMemoryNetworkMapService(private val cacheTimeout: Duration, private val networkMapKeyAndCert: CertificateAndKeyPair) {
private val nodeInfoMap = mutableMapOf<SecureHash, SignedData<NodeInfo>>()
private val nodeInfoMap = mutableMapOf<SecureHash, SignedNodeInfo>()
private val parametersHash = serializedParameters.hash
private val signedParameters = SignedData(
serializedParameters,
DigitalSignature.WithKey(networkMapKeyAndCert.keyPair.public, Crypto.doSign(networkMapKeyAndCert.keyPair.private, serializedParameters.bytes))
)
@POST
@Path("publish")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
fun publishNodeInfo(input: InputStream): Response {
val registrationData = input.readBytes().deserialize<SignedData<NodeInfo>>()
val registrationData = input.readBytes().deserialize<SignedNodeInfo>()
val nodeInfo = registrationData.verified()
val nodeInfoHash = nodeInfo.serialize().sha256()
nodeInfoMap.put(nodeInfoHash, registrationData)
@ -115,7 +117,7 @@ class NetworkMapServer(cacheTimeout: Duration,
@GET
@Produces(MediaType.APPLICATION_OCTET_STREAM)
fun getNetworkMap(): Response {
val networkMap = NetworkMap(nodeInfoMap.keys.map { it }, SecureHash.randomSHA256())
val networkMap = NetworkMap(nodeInfoMap.keys.toList(), parametersHash)
val serializedNetworkMap = networkMap.serialize()
val signature = Crypto.doSign(networkMapKeyAndCert.keyPair.private, serializedNetworkMap.bytes)
val signedNetworkMap = SignedNetworkMap(networkMap.serialize(), DigitalSignatureWithCert(networkMapKeyAndCert.certificate.cert, signature))
@ -143,7 +145,7 @@ class NetworkMapServer(cacheTimeout: Duration,
@Path("network-parameter/{var}")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
fun getNetworkParameter(@PathParam("var") networkParameterHash: String): Response {
return Response.ok(stubNetworkParameter.serialize().bytes).build()
return Response.ok(signedParameters.serialize().bytes).build()
}
@GET

View File

@ -2,6 +2,8 @@ package net.corda.testing.node;
import org.jetbrains.annotations.NotNull;
import static java.util.Collections.emptyList;
@SuppressWarnings("unused")
public class MockNodeFactoryInJavaTest {
private static class CustomNode extends MockNetwork.MockNode {
@ -16,10 +18,10 @@ public class MockNodeFactoryInJavaTest {
@SuppressWarnings("unused")
private static void factoryIsEasyToPassInUsingJava() {
//noinspection Convert2MethodRef
new MockNetwork(new MockNetworkParameters().setDefaultFactory(args -> new CustomNode(args)));
new MockNetwork(new MockNetworkParameters().setDefaultFactory(CustomNode::new));
new MockNetwork(emptyList(), new MockNetworkParameters().setDefaultFactory(args -> new CustomNode(args)));
new MockNetwork(emptyList(), new MockNetworkParameters().setDefaultFactory(CustomNode::new));
//noinspection Convert2MethodRef
new MockNetwork().createNode(new MockNodeParameters(), args -> new CustomNode(args));
new MockNetwork().createNode(new MockNodeParameters(), CustomNode::new);
new MockNetwork(emptyList()).createNode(new MockNodeParameters(), args -> new CustomNode(args));
new MockNetwork(emptyList()).createNode(new MockNodeParameters(), CustomNode::new);
}
}

View File

@ -8,7 +8,7 @@ import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.contextLogger
import net.corda.nodeapi.internal.NetworkParametersCopier
import net.corda.nodeapi.internal.network.NetworkParametersCopier
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.common.internal.asContextEnv
import java.nio.file.Path

View File

@ -1,18 +1,23 @@
package net.corda.testing.common.internal
import net.corda.core.utilities.days
import net.corda.nodeapi.internal.NetworkParameters
import net.corda.nodeapi.internal.NotaryInfo
import net.corda.nodeapi.internal.network.NetworkParameters
import net.corda.nodeapi.internal.network.NotaryInfo
import java.time.Instant
fun testNetworkParameters(notaries: List<NotaryInfo>): NetworkParameters {
fun testNetworkParameters(
notaries: List<NotaryInfo>,
minimumPlatformVersion: Int = 1,
modifiedTime: Instant = Instant.now(),
maxMessageSize: Int = 10485760,
maxTransactionSize: Int = 40000,
epoch: Int = 1
): NetworkParameters {
return NetworkParameters(
minimumPlatformVersion = 1,
minimumPlatformVersion = minimumPlatformVersion,
notaries = notaries,
modifiedTime = Instant.now(),
eventHorizon = 10000.days,
maxMessageSize = 40000,
maxTransactionSize = 40000,
epoch = 1
modifiedTime = modifiedTime,
maxMessageSize = maxMessageSize,
maxTransactionSize = maxTransactionSize,
epoch = epoch
)
}

View File

@ -3,11 +3,9 @@
package net.corda.testing
import net.corda.core.contracts.PartyAndReference
import net.corda.core.contracts.StateRef
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.entropyToKeyPair
import net.corda.core.crypto.generateKeyPair
import net.corda.core.crypto.*
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.Party
import net.corda.core.identity.PartyAndCertificate
@ -15,25 +13,20 @@ import net.corda.core.internal.cert
import net.corda.core.internal.x500Name
import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.loggerFor
import net.corda.node.services.config.configureDevKeyAndTrustStores
import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.crypto.X509CertificateFactory
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.serialization.amqp.AMQP_ENABLED
import org.bouncycastle.asn1.x509.GeneralName
import org.bouncycastle.asn1.x509.GeneralSubtree
import org.bouncycastle.asn1.x509.NameConstraints
import org.bouncycastle.cert.X509CertificateHolder
import org.mockito.Mockito.mock
import org.mockito.internal.stubbing.answers.ThrowsException
import java.lang.reflect.Modifier
import java.math.BigInteger
import java.nio.file.Files
import java.security.KeyPair
import java.security.PublicKey
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
/**
@ -81,7 +74,7 @@ fun freePort(): Int = freePortCounter.getAndAccumulate(0) { prev, _ -> 30000 + (
*/
fun getFreeLocalPorts(hostName: String, numberToAlloc: Int): List<NetworkHostAndPort> {
val freePort = freePortCounter.getAndAccumulate(0) { prev, _ -> 30000 + (prev - 30000 + numberToAlloc) % 10000 }
return (freePort..freePort + numberToAlloc - 1).map { NetworkHostAndPort(hostName, it) }
return (0 until numberToAlloc).map { NetworkHostAndPort(hostName, freePort + it) }
}
fun configureTestSSL(legalName: CordaX500Name): SSLConfiguration = object : SSLConfiguration {
@ -93,18 +86,29 @@ fun configureTestSSL(legalName: CordaX500Name): SSLConfiguration = object : SSLC
configureDevKeyAndTrustStores(legalName)
}
}
fun getTestPartyAndCertificate(party: Party): PartyAndCertificate {
val trustRoot: X509CertificateHolder = DEV_TRUST_ROOT
val intermediate: CertificateAndKeyPair = DEV_CA
val nodeCaName = party.name.copy(commonName = X509Utilities.CORDA_CLIENT_CA_CN)
val nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, party.name.x500Name))), arrayOf())
val issuerKeyPair = Crypto.generateKeyPair(Crypto.ECDSA_SECP256K1_SHA256)
val issuerCertificate = X509Utilities.createCertificate(CertificateType.NODE_CA, intermediate.certificate, intermediate.keyPair, nodeCaName, issuerKeyPair.public,
nameConstraints = nameConstraints)
val nodeCaKeyPair = Crypto.generateKeyPair(X509Utilities.DEFAULT_TLS_SIGNATURE_SCHEME)
val nodeCaCert = X509Utilities.createCertificate(
CertificateType.NODE_CA,
intermediate.certificate,
intermediate.keyPair,
nodeCaName,
nodeCaKeyPair.public,
nameConstraints = NameConstraints(arrayOf(GeneralSubtree(GeneralName(GeneralName.directoryName, party.name.x500Name))), arrayOf()))
val certHolder = X509Utilities.createCertificate(CertificateType.WELL_KNOWN_IDENTITY, issuerCertificate, issuerKeyPair, party.name, party.owningKey)
val pathElements = listOf(certHolder, issuerCertificate, intermediate.certificate, trustRoot)
val identityCert = X509Utilities.createCertificate(
CertificateType.WELL_KNOWN_IDENTITY,
nodeCaCert,
nodeCaKeyPair,
party.name,
party.owningKey)
val pathElements = listOf(identityCert, nodeCaCert, intermediate.certificate, trustRoot)
val certPath = X509CertificateFactory().generateCertPath(pathElements.map(X509CertificateHolder::cert))
return PartyAndCertificate(certPath)
}
@ -116,26 +120,29 @@ fun getTestPartyAndCertificate(name: CordaX500Name, publicKey: PublicKey): Party
return getTestPartyAndCertificate(Party(name, publicKey))
}
class TestIdentity @JvmOverloads constructor(val name: CordaX500Name, entropy: Long? = null) {
val key = if (entropy != null) entropyToKeyPair(BigInteger.valueOf(entropy)) else generateKeyPair()
val pubkey get() = key.public!!
val party = Party(name, pubkey)
val identity by lazy { getTestPartyAndCertificate(party) } // Often not needed.
fun ref(vararg bytes: Byte) = party.ref(*bytes)
}
class TestIdentity(val name: CordaX500Name, val keyPair: KeyPair) {
companion object {
/**
* Creates an identity that won't equal any other. This is mostly useful as a throwaway for test helpers.
* @param organisation the organisation part of the new identity's name.
*/
fun fresh(organisation: String): TestIdentity {
val keyPair = generateKeyPair()
val name = CordaX500Name(organisation, keyPair.public.toStringShort(), CordaX500Name.unspecifiedCountry)
return TestIdentity(name, keyPair)
}
}
@Suppress("unused")
inline fun <reified T : Any> T.kryoSpecific(reason: String, function: () -> Unit) = if (!AMQP_ENABLED) {
function()
} else {
loggerFor<T>().info("Ignoring Kryo specific test, reason: $reason")
}
/** Creates an identity with a deterministic [keyPair] i.e. same [entropy] same keyPair .*/
constructor(name: CordaX500Name, entropy: Long) : this(name, entropyToKeyPair(BigInteger.valueOf(entropy)))
@Suppress("unused")
inline fun <reified T : Any> T.amqpSpecific(reason: String, function: () -> Unit) = if (AMQP_ENABLED) {
function()
} else {
loggerFor<T>().info("Ignoring AMQP specific test, reason: $reason")
/** Creates an identity with the given name and a fresh keyPair. */
constructor(name: CordaX500Name) : this(name, generateKeyPair())
val publicKey: PublicKey get() = keyPair.public
val party: Party = Party(name, publicKey)
val identity: PartyAndCertificate by lazy { getTestPartyAndCertificate(party) } // Often not needed.
fun ref(vararg bytes: Byte): PartyAndReference = party.ref(*bytes)
}
/**
@ -154,25 +161,3 @@ fun NodeInfo.singleIdentityAndCert(): PartyAndCertificate = legalIdentitiesAndCe
* Extract a single identity from the node info. Throws an error if the node has multiple identities.
*/
fun NodeInfo.singleIdentity(): Party = singleIdentityAndCert().party
/**
* A method on a mock was called, but no behaviour was previously specified for that method.
* You can use [com.nhaarman.mockito_kotlin.doReturn] or similar to specify behaviour, see Mockito documentation for details.
*/
class UndefinedMockBehaviorException(message: String) : RuntimeException(message)
inline fun <reified T : Any> rigorousMock() = rigorousMock(T::class.java)
/**
* Create a Mockito mock that has [UndefinedMockBehaviorException] as the default behaviour of all abstract methods,
* and [org.mockito.invocation.InvocationOnMock.callRealMethod] as the default for all concrete methods.
* @param T the type to mock. Note if you want concrete methods of a Kotlin interface to be invoked,
* it won't work unless you mock a (trivial) abstract implementation of that interface instead.
*/
fun <T> rigorousMock(clazz: Class<T>): T = mock(clazz) {
if (Modifier.isAbstract(it.method.modifiers)) {
// Use ThrowsException to hack the stack trace, and lazily so we can customise the message:
ThrowsException(UndefinedMockBehaviorException("Please specify what should happen when '${it.method}' is called, or don't call it. Args: ${Arrays.toString(it.arguments)}")).answer(it)
} else {
it.callRealMethod()
}
}

View File

@ -1,25 +0,0 @@
package net.corda.testing
import java.time.Duration
/**
* Ideas borrowed from "io.kotlintest" with some improvements made
* This is meant for use from Kotlin code use only mainly due to it's inline/reified nature
*/
inline fun <reified E : Throwable, R> eventually(duration: Duration, f: () -> R): R {
val end = System.nanoTime() + duration.toNanos()
var times = 0
while (System.nanoTime() < end) {
try {
return f()
} catch (e: Throwable) {
when (e) {
is E -> {
}// ignore and continue
else -> throw e // unexpected exception type - rethrow
}
}
times++
}
throw AssertionError("Test failed after $duration; attempted $times times")
}

View File

@ -1,54 +0,0 @@
package net.corda.testing
import net.corda.core.internal.uncheckedCast
import kotlin.reflect.KCallable
import kotlin.reflect.jvm.reflect
/**
* These functions may be used to run measurements of a function where the parameters are chosen from corresponding
* [Iterable]s in a lexical manner. An example use case would be benchmarking the speed of a certain function call using
* different combinations of parameters.
*/
fun <A : Any, R> measure(a: Iterable<A>, f: (A) -> R) =
measure(listOf(a), f.reflect()!!) { f(uncheckedCast(it[0])) }
fun <A : Any, B : Any, R> measure(a: Iterable<A>, b: Iterable<B>, f: (A, B) -> R) =
measure(listOf(a, b), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1])) }
fun <A : Any, B : Any, C : Any, R> measure(a: Iterable<A>, b: Iterable<B>, c: Iterable<C>, f: (A, B, C) -> R) =
measure(listOf(a, b, c), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2])) }
fun <A : Any, B : Any, C : Any, D : Any, R> measure(a: Iterable<A>, b: Iterable<B>, c: Iterable<C>, d: Iterable<D>, f: (A, B, C, D) -> R) =
measure(listOf(a, b, c, d), f.reflect()!!) { f(uncheckedCast(it[0]), uncheckedCast(it[1]), uncheckedCast(it[2]), uncheckedCast(it[3])) }
private fun <R> measure(paramIterables: List<Iterable<Any?>>, kCallable: KCallable<R>, call: (Array<Any?>) -> R): Iterable<MeasureResult<R>> {
val kParameters = kCallable.parameters
return iterateLexical(paramIterables).map { params ->
MeasureResult(
// For example an underscore param in a lambda does not have a name:
parameters = params.mapIndexed { index, param -> Pair(kParameters[index].name, param) },
result = call(params.toTypedArray())
)
}
}
data class MeasureResult<out R>(
val parameters: List<Pair<String?, Any?>>,
val result: R
)
fun <A> iterateLexical(iterables: List<Iterable<A>>): Iterable<List<A>> {
val result = ArrayList<List<A>>()
fun iterateLexicalHelper(index: Int, list: List<A>) {
if (index < iterables.size) {
iterables[index].forEach {
iterateLexicalHelper(index + 1, list + it)
}
} else {
result.add(list)
}
}
iterateLexicalHelper(0, emptyList())
return result
}

View File

@ -9,6 +9,7 @@ import net.corda.nodeapi.internal.serialization.*
import net.corda.nodeapi.internal.serialization.amqp.AMQPClientSerializationScheme
import net.corda.nodeapi.internal.serialization.amqp.AMQPServerSerializationScheme
import net.corda.testing.common.internal.asContextEnv
import net.corda.testing.internal.rigorousMock
import net.corda.testing.internal.testThreadFactory
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnector
import org.junit.rules.TestRule
@ -33,19 +34,30 @@ class SerializationEnvironmentRule(private val inheritable: Boolean = false) : T
}.whenever(it).execute(any())
}
}
/** Do not call, instead use [SerializationEnvironmentRule] as a [org.junit.Rule]. */
fun <T> run(taskLabel: String, task: (SerializationEnvironment) -> T): T {
return SerializationEnvironmentRule().apply { init(taskLabel) }.runTask(task)
}
}
lateinit var env: SerializationEnvironment
override fun apply(base: Statement, description: Description): Statement {
env = createTestSerializationEnv(description.toString())
init(description.toString())
return object : Statement() {
override fun evaluate() {
try {
env.asContextEnv(inheritable) { base.evaluate() }
} finally {
inVMExecutors.remove(env)
}
}
override fun evaluate() = runTask { base.evaluate() }
}
}
private fun init(envLabel: String) {
env = createTestSerializationEnv(envLabel)
}
private fun <T> runTask(task: (SerializationEnvironment) -> T): T {
try {
return env.asContextEnv(inheritable, task)
} finally {
inVMExecutors.remove(env)
}
}
}
@ -55,25 +67,6 @@ interface GlobalSerializationEnvironment : SerializationEnvironment {
fun unset()
}
/** @param inheritable whether new threads inherit the environment, use sparingly. */
fun <T> withTestSerialization(inheritable: Boolean = false, callable: (SerializationEnvironment) -> T): T {
return createTestSerializationEnv("<context>").asContextEnv(inheritable, callable)
}
/**
* For example your test class uses [SerializationEnvironmentRule] but you want to turn it off for one method.
* Use sparingly, ideally a test class shouldn't mix serializers init mechanisms.
*/
fun <T> withoutTestSerialization(callable: () -> T): T {
val (property, env) = listOf(_contextSerializationEnv, _inheritableContextSerializationEnv).map { Pair(it, it.get()) }.single { it.second != null }
property.set(null)
try {
return callable()
} finally {
property.set(env)
}
}
/**
* Should only be used by Driver and MockNode.
* @param armed true to install, false to do nothing and return a dummy env.
@ -95,22 +88,21 @@ fun setGlobalSerialization(armed: Boolean): GlobalSerializationEnvironment {
}
}
private fun createTestSerializationEnv(label: String) = object : SerializationEnvironmentImpl(
SerializationFactoryImpl().apply {
registerScheme(KryoClientSerializationScheme())
registerScheme(KryoServerSerializationScheme())
registerScheme(AMQPClientSerializationScheme(emptyList()))
registerScheme(AMQPServerSerializationScheme(emptyList()))
},
AMQP_P2P_CONTEXT,
KRYO_RPC_SERVER_CONTEXT,
KRYO_RPC_CLIENT_CONTEXT,
AMQP_STORAGE_CONTEXT,
KRYO_CHECKPOINT_CONTEXT) {
override fun toString() = "testSerializationEnv($label)"
private fun createTestSerializationEnv(label: String): SerializationEnvironmentImpl {
val factory = SerializationFactoryImpl().apply {
registerScheme(KryoClientSerializationScheme())
registerScheme(KryoServerSerializationScheme())
registerScheme(AMQPClientSerializationScheme(emptyList()))
registerScheme(AMQPServerSerializationScheme(emptyList()))
}
return object : SerializationEnvironmentImpl(
factory,
AMQP_P2P_CONTEXT,
KRYO_RPC_SERVER_CONTEXT,
KRYO_RPC_CLIENT_CONTEXT,
AMQP_STORAGE_CONTEXT,
KRYO_CHECKPOINT_CONTEXT
) {
override fun toString() = "testSerializationEnv($label)"
}
}
private const val AMQP_ENABLE_PROP_NAME = "net.corda.testing.amqp.enable"
// TODO: Remove usages of this function when we fully switched to AMQP
private fun isAmqpEnabled(): Boolean = java.lang.Boolean.getBoolean(AMQP_ENABLE_PROP_NAME)

View File

@ -13,14 +13,23 @@ import java.security.PublicKey
import java.time.Instant
// A dummy time at which we will be pretending test transactions are created.
val TEST_TX_TIME: Instant get() = Instant.parse("2015-04-17T12:00:00.00Z")
@JvmField
val TEST_TX_TIME = Instant.parse("2015-04-17T12:00:00.00Z")
@JvmField
val DUMMY_NOTARY_NAME = CordaX500Name("Notary Service", "Zurich", "CH")
@JvmField
val DUMMY_BANK_A_NAME = CordaX500Name("Bank A", "London", "GB")
@JvmField
val DUMMY_BANK_B_NAME = CordaX500Name("Bank B", "New York", "US")
@JvmField
val DUMMY_BANK_C_NAME = CordaX500Name("Bank C", "Tokyo", "JP")
@JvmField
val BOC_NAME = CordaX500Name("BankOfCorda", "London", "GB")
@JvmField
val ALICE_NAME = CordaX500Name("Alice Corp", "Madrid", "ES")
@JvmField
val BOB_NAME = CordaX500Name("Bob Plc", "Rome", "IT")
@JvmField
val CHARLIE_NAME = CordaX500Name("Charlie Ltd", "Athens", "GR")
val DEV_CA: CertificateAndKeyPair by lazy {
// TODO: Should be identity scheme
@ -42,3 +51,6 @@ val DEV_TRUST_ROOT: X509CertificateHolder by lazy {
fun dummyCommand(vararg signers: PublicKey = arrayOf(generateKeyPair().public)) = Command<TypeOnlyCommandData>(DummyCommandData, signers.toList())
object DummyCommandData : TypeOnlyCommandData()
/** Maximum artemis message size. 10 MiB maximum allowed file size for attachments, including message headers. */
const val MAX_MESSAGE_SIZE: Int = 10485760

View File

@ -1,10 +0,0 @@
package net.corda.testing
import org.junit.Rule
@Deprecated("Instead of extending this class, use SerializationEnvironmentRule in the same way.")
abstract class TestDependencyInjectionBase {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
}

View File

@ -1,20 +0,0 @@
package net.corda.testing
import net.corda.testing.TestTimestamp.Companion.timestamp
import java.text.SimpleDateFormat
import java.util.*
/**
* [timestamp] holds a formatted (UTC) timestamp that's set the first time it is queried. This is used to
* provide a uniform timestamp for tests.
*/
class TestTimestamp {
companion object {
val timestamp: String = {
val tz = TimeZone.getTimeZone("UTC")
val df = SimpleDateFormat("yyyyMMddHHmmss")
df.timeZone = tz
df.format(Date())
}()
}
}

View File

@ -1,4 +1,4 @@
package net.corda.testing
package net.corda.testing.dsl
import net.corda.core.contracts.ContractState
import net.corda.core.contracts.StateAndRef

View File

@ -1,4 +1,4 @@
package net.corda.testing
package net.corda.testing.dsl
import net.corda.core.contracts.*
import net.corda.core.cordapp.CordappProvider
@ -12,9 +12,9 @@ import net.corda.core.node.ServicesForResolution
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction
import net.corda.testing.contracts.DummyContract
import net.corda.testing.services.MockAttachmentStorage
import net.corda.testing.services.MockCordappProvider
import net.corda.testing.dummyCommand
import java.io.InputStream
import java.security.PublicKey
import java.util.*

View File

@ -1,4 +1,4 @@
package net.corda.testing
package net.corda.testing.dsl
import net.corda.core.contracts.AlwaysAcceptAttachmentConstraint
import net.corda.core.contracts.Attachment

View File

@ -0,0 +1,19 @@
package net.corda.testing.internal
import net.corda.core.serialization.internal._contextSerializationEnv
import net.corda.core.serialization.internal._inheritableContextSerializationEnv
import net.corda.testing.SerializationEnvironmentRule
/**
* For example your test class uses [SerializationEnvironmentRule] but you want to turn it off for one method.
* Use sparingly, ideally a test class shouldn't mix serializers init mechanisms.
*/
fun <T> withoutTestSerialization(callable: () -> T): T { // TODO: Delete this, see CORDA-858.
val (property, env) = listOf(_contextSerializationEnv, _inheritableContextSerializationEnv).map { Pair(it, it.get()) }.single { it.second != null }
property.set(null)
try {
return callable()
} finally {
property.set(env)
}
}

View File

@ -0,0 +1,44 @@
package net.corda.testing.internal
import net.corda.core.utilities.loggerFor
import net.corda.nodeapi.internal.serialization.amqp.AMQP_ENABLED
import org.mockito.Mockito
import org.mockito.internal.stubbing.answers.ThrowsException
import java.lang.reflect.Modifier
import java.util.*
@Suppress("unused")
inline fun <reified T : Any> T.kryoSpecific(reason: String, function: () -> Unit) = if (!AMQP_ENABLED) {
function()
} else {
loggerFor<T>().info("Ignoring Kryo specific test, reason: $reason")
}
@Suppress("unused")
inline fun <reified T : Any> T.amqpSpecific(reason: String, function: () -> Unit) = if (AMQP_ENABLED) {
function()
} else {
loggerFor<T>().info("Ignoring AMQP specific test, reason: $reason")
}
/**
* A method on a mock was called, but no behaviour was previously specified for that method.
* You can use [com.nhaarman.mockito_kotlin.doReturn] or similar to specify behaviour, see Mockito documentation for details.
*/
class UndefinedMockBehaviorException(message: String) : RuntimeException(message)
inline fun <reified T : Any> rigorousMock() = rigorousMock(T::class.java)
/**
* Create a Mockito mock that has [UndefinedMockBehaviorException] as the default behaviour of all abstract methods,
* and [org.mockito.invocation.InvocationOnMock.callRealMethod] as the default for all concrete methods.
* @param T the type to mock. Note if you want concrete methods of a Kotlin interface to be invoked,
* it won't work unless you mock a (trivial) abstract implementation of that interface instead.
*/
fun <T> rigorousMock(clazz: Class<T>): T = Mockito.mock(clazz) {
if (Modifier.isAbstract(it.method.modifiers)) {
// Use ThrowsException to hack the stack trace, and lazily so we can customise the message:
ThrowsException(UndefinedMockBehaviorException("Please specify what should happen when '${it.method}' is called, or don't call it. Args: ${Arrays.toString(it.arguments)}")).answer(it)
} else {
it.callRealMethod()
}
}

View File

@ -1,4 +1,4 @@
package net.corda.testing
package net.corda.testing.internal
import net.corda.core.internal.packageName
import org.apache.logging.log4j.Level

View File

@ -0,0 +1,55 @@
package net.corda.testing.internal
import net.corda.core.crypto.Crypto
import net.corda.core.crypto.sign
import net.corda.core.identity.CordaX500Name
import net.corda.core.identity.PartyAndCertificate
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.serialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.SignedNodeInfo
import net.corda.testing.getTestPartyAndCertificate
import java.security.PrivateKey
class TestNodeInfoBuilder {
private val identitiesAndPrivateKeys = ArrayList<Pair<PartyAndCertificate, PrivateKey>>()
fun addIdentity(name: CordaX500Name): Pair<PartyAndCertificate, PrivateKey> {
val identityKeyPair = Crypto.generateKeyPair()
val identity = getTestPartyAndCertificate(name, identityKeyPair.public)
return Pair(identity, identityKeyPair.private).also {
identitiesAndPrivateKeys += it
}
}
fun build(serial: Long = 1): NodeInfo {
return NodeInfo(
listOf(NetworkHostAndPort("my.${identitiesAndPrivateKeys[0].first.party.name.organisation}.com", 1234)),
identitiesAndPrivateKeys.map { it.first },
1,
serial
)
}
fun buildWithSigned(serial: Long = 1): Pair<NodeInfo, SignedNodeInfo> {
val nodeInfo = build(serial)
val privateKeys = identitiesAndPrivateKeys.map { it.second }
return Pair(nodeInfo, nodeInfo.signWith(privateKeys))
}
fun reset() {
identitiesAndPrivateKeys.clear()
}
}
fun createNodeInfoAndSigned(vararg names: CordaX500Name, serial: Long = 1): Pair<NodeInfo, SignedNodeInfo> {
val nodeInfoBuilder = TestNodeInfoBuilder()
names.forEach { nodeInfoBuilder.addIdentity(it) }
return nodeInfoBuilder.buildWithSigned(serial)
}
fun NodeInfo.signWith(keys: List<PrivateKey>): SignedNodeInfo {
val serialized = serialize()
val signatures = keys.map { it.sign(serialized.bytes) }
return SignedNodeInfo(serialized, signatures)
}

View File

@ -1,4 +1,4 @@
package net.corda.testing.contracts
package net.corda.testing.internal.vault
import net.corda.core.contracts.Contract
import net.corda.core.contracts.UniqueIdentifier
@ -10,9 +10,8 @@ import net.corda.core.schemas.QueryableState
import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.finance.contracts.DealState
import net.corda.testing.schemas.DummyDealStateSchemaV1
val DUMMY_DEAL_PROGRAM_ID = "net.corda.testing.contracts.DummyDealContract"
val DUMMY_DEAL_PROGRAM_ID = "net.corda.testing.internal.vault.DummyDealContract"
class DummyDealContract : Contract {
override fun verify(tx: LedgerTransaction) {}

View File

@ -1,4 +1,4 @@
package net.corda.testing.schemas
package net.corda.testing.internal.vault
import net.corda.core.contracts.UniqueIdentifier
import net.corda.core.identity.AbstractParty

View File

@ -1,4 +1,4 @@
package net.corda.testing.contracts
package net.corda.testing.internal.vault
import net.corda.core.contracts.Contract
import net.corda.core.contracts.LinearState
@ -10,12 +10,10 @@ import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState
import net.corda.core.schemas.QueryableState
import net.corda.core.transactions.LedgerTransaction
import net.corda.testing.schemas.DummyLinearStateSchemaV1
import net.corda.testing.schemas.DummyLinearStateSchemaV2
import java.time.LocalDateTime
import java.time.ZoneOffset.UTC
const val DUMMY_LINEAR_CONTRACT_PROGRAM_ID = "net.corda.testing.contracts.DummyLinearContract"
const val DUMMY_LINEAR_CONTRACT_PROGRAM_ID = "net.corda.testing.internal.vault.DummyLinearContract"
class DummyLinearContract : Contract {
override fun verify(tx: LedgerTransaction) {

View File

@ -1,4 +1,4 @@
package net.corda.testing.schemas
package net.corda.testing.internal.vault
import net.corda.core.contracts.ContractState
import net.corda.core.identity.AbstractParty

View File

@ -1,4 +1,4 @@
package net.corda.testing.schemas
package net.corda.testing.internal.vault
import net.corda.core.contracts.UniqueIdentifier
import net.corda.core.identity.AbstractParty

View File

@ -1,6 +1,4 @@
@file:JvmName("VaultFiller")
package net.corda.testing.contracts
package net.corda.testing.internal.vault
import net.corda.core.contracts.*
import net.corda.core.crypto.Crypto
@ -80,7 +78,7 @@ class VaultFiller @JvmOverloads constructor(
addCommand(dummyCommand())
}
val stx = issuerServices.signInitialTransaction(dummyIssue)
return@map services.addSignature(stx, defaultNotary.pubkey)
return@map services.addSignature(stx, defaultNotary.publicKey)
}
services.recordTransactions(transactions)
// Get all the StateAndRefs of all the generated transactions.
@ -101,7 +99,7 @@ class VaultFiller @JvmOverloads constructor(
linearTimestamp: Instant = now()): Vault<LinearState> {
val myKey: PublicKey = services.myInfo.chooseIdentity().owningKey
val me = AnonymousParty(myKey)
val issuerKey = defaultNotary.key
val issuerKey = defaultNotary.keyPair
val signatureMetadata = SignatureMetadata(services.myInfo.platformVersion, Crypto.findSignatureScheme(issuerKey.public).schemeNumberID)
val transactions: List<SignedTransaction> = (1..numberToCreate).map {
// Issue a Linear state

View File

@ -1,47 +0,0 @@
package net.corda.testing.messaging
import net.corda.core.identity.CordaX500Name
import net.corda.core.serialization.internal.nodeSerializationEnv
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.ArtemisTcpTransport
import net.corda.nodeapi.ConnectionDirection
import net.corda.nodeapi.internal.config.SSLConfiguration
import net.corda.testing.configureTestSSL
import org.apache.activemq.artemis.api.core.client.*
/**
* As the name suggests this is a simple client for connecting to MQ brokers.
*/
class SimpleMQClient(val target: NetworkHostAndPort,
private val config: SSLConfiguration? = configureTestSSL(DEFAULT_MQ_LEGAL_NAME)) {
companion object {
val DEFAULT_MQ_LEGAL_NAME = CordaX500Name(organisation = "SimpleMQClient", locality = "London", country = "GB")
}
lateinit var sessionFactory: ClientSessionFactory
lateinit var session: ClientSession
lateinit var producer: ClientProducer
fun start(username: String? = null, password: String? = null, enableSSL: Boolean = true) {
val tcpTransport = ArtemisTcpTransport.tcpTransport(ConnectionDirection.Outbound(), target, config, enableSSL = enableSSL)
val locator = ActiveMQClient.createServerLocatorWithoutHA(tcpTransport).apply {
isBlockOnNonDurableSend = true
threadPoolMaxSize = 1
isUseGlobalPools = nodeSerializationEnv != null
}
sessionFactory = locator.createSessionFactory()
session = sessionFactory.createSession(username, password, false, true, true, locator.isPreAcknowledge, locator.ackBatchSize)
session.start()
producer = session.createProducer()
}
fun createMessage(): ClientMessage = session.createMessage(false)
fun stop() {
try {
sessionFactory.close()
} catch (e: Exception) {
// sessionFactory might not have initialised.
}
}
}

View File

@ -0,0 +1,27 @@
package net.corda.testing
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
class TestIdentityTests {
@Test
fun `entropy works`() {
val a = TestIdentity(ALICE_NAME, 123)
val b = TestIdentity(BOB_NAME, 123)
assertEquals(a.publicKey, b.publicKey)
assertEquals(a.keyPair.private, b.keyPair.private)
}
@Test
fun `fresh works`() {
val x = TestIdentity.fresh("xx")
val y = TestIdentity.fresh("yy")
// The param is called organisation so we'd better use it as such:
assertEquals("xx", x.name.organisation)
assertEquals("yy", y.name.organisation)
// A fresh identity shouldn't be equal to anything by accident:
assertNotEquals(x.name, y.name)
assertNotEquals(x.publicKey, y.publicKey)
}
}