Merged in clint-irsintegrationfix (pull request #412)

Fixes the IRS integration tests in the IRS repo.
This commit is contained in:
Clinton Alexander 2016-10-24 16:53:46 +00:00
commit 3ec6490d0a
8 changed files with 91 additions and 26 deletions

View File

@ -25,8 +25,8 @@ class CordaRPCClientTest {
val driverStarted = CountDownLatch(1) val driverStarted = CountDownLatch(1)
driverThread = thread { driverThread = thread {
driver { driver {
val nodeInfo = startNode().get() val driverInfo = startNode().get()
client = CordaRPCClient(toHostAndPort(nodeInfo.address), configureTestSSL()) client = CordaRPCClient(toHostAndPort(driverInfo.nodeInfo.address), configureTestSSL())
driverStarted.countDown() driverStarted.countDown()
stopDriver.await() stopDriver.await()
} }

View File

@ -51,9 +51,9 @@ class NodeMonitorModelTest {
val aliceNodeFuture = startNode("Alice") val aliceNodeFuture = startNode("Alice")
val notaryNodeFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))) val notaryNodeFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
aliceNode = aliceNodeFuture.get() aliceNode = aliceNodeFuture.get().nodeInfo
notaryNode = notaryNodeFuture.get() notaryNode = notaryNodeFuture.get().nodeInfo
newNode = { nodeName -> startNode(nodeName).get() } newNode = { nodeName -> startNode(nodeName).get().nodeInfo }
val monitor = NodeMonitorModel() val monitor = NodeMonitorModel()
stateMachineTransactionMapping = monitor.stateMachineTransactionMapping.bufferUntilSubscribed() stateMachineTransactionMapping = monitor.stateMachineTransactionMapping.bufferUntilSubscribed()

View File

@ -32,8 +32,8 @@ class Main : App() {
val aliceNodeFuture = startNode("Alice") val aliceNodeFuture = startNode("Alice")
val notaryNodeFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type))) val notaryNodeFuture = startNode("Notary", advertisedServices = setOf(ServiceInfo(SimpleNotaryService.type)))
val aliceNode = aliceNodeFuture.get() val aliceNode = aliceNodeFuture.get().nodeInfo
val notaryNode = notaryNodeFuture.get() val notaryNode = notaryNodeFuture.get().nodeInfo
Models.get<IdentityModel>(Main::class).notary.set(notaryNode.notaryIdentity) Models.get<IdentityModel>(Main::class).notary.set(notaryNode.notaryIdentity)
Models.get<IdentityModel>(Main::class).myIdentity.set(aliceNode.legalIdentity) Models.get<IdentityModel>(Main::class).myIdentity.set(aliceNode.legalIdentity)

View File

@ -30,31 +30,31 @@ class DriverTests {
val notary = startNode("TestNotary", setOf(ServiceInfo(SimpleNotaryService.type))) val notary = startNode("TestNotary", setOf(ServiceInfo(SimpleNotaryService.type)))
val regulator = startNode("Regulator", setOf(ServiceInfo(RegulatorService.type))) val regulator = startNode("Regulator", setOf(ServiceInfo(RegulatorService.type)))
nodeMustBeUp(notary.get(), "TestNotary") nodeMustBeUp(notary.get().nodeInfo, "TestNotary")
nodeMustBeUp(regulator.get(), "Regulator") nodeMustBeUp(regulator.get().nodeInfo, "Regulator")
Pair(notary.get(), regulator.get()) Pair(notary.get(), regulator.get())
} }
nodeMustBeDown(notary) nodeMustBeDown(notary.nodeInfo)
nodeMustBeDown(regulator) nodeMustBeDown(regulator.nodeInfo)
} }
@Test @Test
fun startingNodeWithNoServicesWorks() { fun startingNodeWithNoServicesWorks() {
val noService = driver { val noService = driver {
val noService = startNode("NoService") val noService = startNode("NoService")
nodeMustBeUp(noService.get(), "NoService") nodeMustBeUp(noService.get().nodeInfo, "NoService")
noService.get() noService.get()
} }
nodeMustBeDown(noService) nodeMustBeDown(noService.nodeInfo)
} }
@Test @Test
fun randomFreePortAllocationWorks() { fun randomFreePortAllocationWorks() {
val nodeInfo = driver(portAllocation = PortAllocation.RandomFree()) { val nodeInfo = driver(portAllocation = PortAllocation.RandomFree()) {
val nodeInfo = startNode("NoService") val nodeInfo = startNode("NoService")
nodeMustBeUp(nodeInfo.get(), "NoService") nodeMustBeUp(nodeInfo.get().nodeInfo, "NoService")
nodeInfo.get() nodeInfo.get()
} }
nodeMustBeDown(nodeInfo) nodeMustBeDown(nodeInfo.nodeInfo)
} }
} }

View File

@ -5,12 +5,17 @@ import com.fasterxml.jackson.databind.module.SimpleModule
import com.google.common.net.HostAndPort import com.google.common.net.HostAndPort
import com.r3corda.core.ThreadBox import com.r3corda.core.ThreadBox
import com.r3corda.core.crypto.Party import com.r3corda.core.crypto.Party
import com.r3corda.core.crypto.generateKeyPair
import com.r3corda.core.node.NodeInfo import com.r3corda.core.node.NodeInfo
import com.r3corda.core.node.services.NetworkMapCache
import com.r3corda.core.node.services.ServiceInfo import com.r3corda.core.node.services.ServiceInfo
import com.r3corda.node.serialization.NodeClock
import com.r3corda.node.services.config.ConfigHelper import com.r3corda.node.services.config.ConfigHelper
import com.r3corda.node.services.config.FullNodeConfiguration import com.r3corda.node.services.config.FullNodeConfiguration
import com.r3corda.node.services.messaging.ArtemisMessagingComponent
import com.r3corda.node.services.messaging.ArtemisMessagingServer import com.r3corda.node.services.messaging.ArtemisMessagingServer
import com.r3corda.node.services.messaging.NodeMessagingClient import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.network.InMemoryNetworkMapCache
import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.utilities.JsonSupport import com.r3corda.node.utilities.JsonSupport
import com.typesafe.config.Config import com.typesafe.config.Config
@ -23,11 +28,13 @@ import java.net.*
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.time.Clock
import java.util.* import java.util.*
import java.util.concurrent.* import java.util.concurrent.*
import kotlin.concurrent.thread
/** /**
* This file defines a small "Driver" DSL for starting up nodes. * This file defines a small "Driver" DSL for starting up nodes that is only intended for development, demos and tests.
* *
* The process the driver is run in behaves as an Artemis client and starts up other processes. Namely it first * The process the driver is run in behaves as an Artemis client and starts up other processes. Namely it first
* bootstraps a network map service to allow the specified nodes to connect to, then starts up the actual nodes. * bootstraps a network map service to allow the specified nodes to connect to, then starts up the actual nodes.
@ -52,7 +59,7 @@ interface DriverDSLExposedInterface {
* @param advertisedServices The set of services to be advertised by the node. Defaults to empty set. * @param advertisedServices The set of services to be advertised by the node. Defaults to empty set.
* @return The [NodeInfo] of the started up node retrieved from the network map service. * @return The [NodeInfo] of the started up node retrieved from the network map service.
*/ */
fun startNode(providedName: String? = null, advertisedServices: Set<ServiceInfo> = setOf()): Future<NodeInfo> fun startNode(providedName: String? = null, advertisedServices: Set<ServiceInfo> = setOf()): Future<NodeInfoAndConfig>
fun waitForAllNodesToFinish() fun waitForAllNodesToFinish()
} }
@ -62,6 +69,8 @@ interface DriverDSLInternalInterface : DriverDSLExposedInterface {
fun shutdown() fun shutdown()
} }
data class NodeInfoAndConfig(val nodeInfo: NodeInfo, val config: Config)
sealed class PortAllocation { sealed class PortAllocation {
abstract fun nextPort(): Int abstract fun nextPort(): Int
fun nextHostAndPort(): HostAndPort = HostAndPort.fromParts("localhost", nextPort()) fun nextHostAndPort(): HostAndPort = HostAndPort.fromParts("localhost", nextPort())
@ -98,6 +107,7 @@ sealed class PortAllocation {
* and may be specified in [DriverDSL.startNode]. * and may be specified in [DriverDSL.startNode].
* @param portAllocation The port allocation strategy to use for the messaging and the web server addresses. Defaults to incremental. * @param portAllocation The port allocation strategy to use for the messaging and the web server addresses. Defaults to incremental.
* @param debugPortAllocation The port allocation strategy to use for jvm debugging. Defaults to incremental. * @param debugPortAllocation The port allocation strategy to use for jvm debugging. Defaults to incremental.
* @param useTestClock If true the test clock will be used in Node.
* @param isDebug Indicates whether the spawned nodes should start in jdwt debug mode. * @param isDebug Indicates whether the spawned nodes should start in jdwt debug mode.
* @param dsl The dsl itself. * @param dsl The dsl itself.
* @return The value returned in the [dsl] closure. * @return The value returned in the [dsl] closure.
@ -106,6 +116,7 @@ fun <A> driver(
baseDirectory: String = "build/${getTimestampAsDirectoryName()}", baseDirectory: String = "build/${getTimestampAsDirectoryName()}",
portAllocation: PortAllocation = PortAllocation.Incremental(10000), portAllocation: PortAllocation = PortAllocation.Incremental(10000),
debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005), debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005),
useTestClock: Boolean = false,
isDebug: Boolean = false, isDebug: Boolean = false,
dsl: DriverDSLExposedInterface.() -> A dsl: DriverDSLExposedInterface.() -> A
) = genericDriver( ) = genericDriver(
@ -113,6 +124,7 @@ fun <A> driver(
portAllocation = portAllocation, portAllocation = portAllocation,
debugPortAllocation = debugPortAllocation, debugPortAllocation = debugPortAllocation,
baseDirectory = baseDirectory, baseDirectory = baseDirectory,
useTestClock = useTestClock,
isDebug = isDebug isDebug = isDebug
), ),
coerce = { it }, coerce = { it },
@ -192,10 +204,11 @@ fun <A> poll(pollName: String, pollIntervalMs: Long = 500, warnCount: Int = 120,
return result return result
} }
class DriverDSL( open class DriverDSL(
val portAllocation: PortAllocation, val portAllocation: PortAllocation,
val debugPortAllocation: PortAllocation, val debugPortAllocation: PortAllocation,
val baseDirectory: String, val baseDirectory: String,
val useTestClock: Boolean,
val isDebug: Boolean val isDebug: Boolean
) : DriverDSLInternalInterface { ) : DriverDSLInternalInterface {
private val networkMapName = "NetworkMapService" private val networkMapName = "NetworkMapService"
@ -276,7 +289,7 @@ class DriverDSL(
} }
} }
override fun startNode(providedName: String?, advertisedServices: Set<ServiceInfo>): Future<NodeInfo> { override fun startNode(providedName: String?, advertisedServices: Set<ServiceInfo>): Future<NodeInfoAndConfig> {
val messagingAddress = portAllocation.nextHostAndPort() val messagingAddress = portAllocation.nextHostAndPort()
val apiAddress = portAllocation.nextHostAndPort() val apiAddress = portAllocation.nextHostAndPort()
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
@ -293,13 +306,14 @@ class DriverDSL(
"artemisAddress" to messagingAddress.toString(), "artemisAddress" to messagingAddress.toString(),
"webAddress" to apiAddress.toString(), "webAddress" to apiAddress.toString(),
"extraAdvertisedServiceIds" to advertisedServices.joinToString(","), "extraAdvertisedServiceIds" to advertisedServices.joinToString(","),
"networkMapAddress" to networkMapAddress.toString() "networkMapAddress" to networkMapAddress.toString(),
"useTestClock" to useTestClock
) )
) )
return Executors.newSingleThreadExecutor().submit(Callable<NodeInfo> { return Executors.newSingleThreadExecutor().submit(Callable<NodeInfoAndConfig> {
registerProcess(DriverDSL.startNode(config, quasarJarPath, debugPort)) registerProcess(DriverDSL.startNode(config, quasarJarPath, debugPort))
queryNodeInfo(apiAddress)!! NodeInfoAndConfig(queryNodeInfo(apiAddress)!!, config)
}) })
} }
@ -312,7 +326,6 @@ class DriverDSL(
val debugPort = if (isDebug) debugPortAllocation.nextPort() else null val debugPort = if (isDebug) debugPortAllocation.nextPort() else null
val nodeDirectory = "$baseDirectory/$networkMapName" val nodeDirectory = "$baseDirectory/$networkMapName"
val config = ConfigHelper.loadConfig( val config = ConfigHelper.loadConfig(
baseDirectoryPath = Paths.get(nodeDirectory), baseDirectoryPath = Paths.get(nodeDirectory),
allowMissingConfig = true, allowMissingConfig = true,
@ -321,7 +334,8 @@ class DriverDSL(
"basedir" to Paths.get(nodeDirectory).normalize().toString(), "basedir" to Paths.get(nodeDirectory).normalize().toString(),
"artemisAddress" to networkMapAddress.toString(), "artemisAddress" to networkMapAddress.toString(),
"webAddress" to apiAddress.toString(), "webAddress" to apiAddress.toString(),
"extraAdvertisedServiceIds" to "" "extraAdvertisedServiceIds" to "",
"useTestClock" to useTestClock
) )
) )

View File

@ -5,10 +5,13 @@ import com.r3corda.core.div
import com.r3corda.core.messaging.SingleMessageRecipient import com.r3corda.core.messaging.SingleMessageRecipient
import com.r3corda.core.node.services.ServiceInfo import com.r3corda.core.node.services.ServiceInfo
import com.r3corda.node.internal.Node import com.r3corda.node.internal.Node
import com.r3corda.node.serialization.NodeClock
import com.r3corda.node.services.messaging.NodeMessagingClient import com.r3corda.node.services.messaging.NodeMessagingClient
import com.r3corda.node.services.network.NetworkMapService import com.r3corda.node.services.network.NetworkMapService
import com.r3corda.node.utilities.TestClock
import com.typesafe.config.Config import com.typesafe.config.Config
import java.nio.file.Path import java.nio.file.Path
import java.time.Clock
import java.util.* import java.util.*
interface NodeSSLConfiguration { interface NodeSSLConfiguration {
@ -46,8 +49,12 @@ class FullNodeConfiguration(config: Config) : NodeConfiguration {
val webAddress: HostAndPort by config val webAddress: HostAndPort by config
val messagingServerAddress: HostAndPort? by config.getOrElse { null } val messagingServerAddress: HostAndPort? by config.getOrElse { null }
val extraAdvertisedServiceIds: String by config val extraAdvertisedServiceIds: String by config
val useTestClock: Boolean by config.getOrElse { false }
fun createNode(): Node { fun createNode(): Node {
// This is a sanity feature do not remove.
require(!useTestClock || devMode) { "Cannot use test clock outside of dev mode" }
val advertisedServices = mutableSetOf<ServiceInfo>() val advertisedServices = mutableSetOf<ServiceInfo>()
if (!extraAdvertisedServiceIds.isNullOrEmpty()) { if (!extraAdvertisedServiceIds.isNullOrEmpty()) {
for (serviceId in extraAdvertisedServiceIds.split(",")) { for (serviceId in extraAdvertisedServiceIds.split(",")) {
@ -56,7 +63,7 @@ class FullNodeConfiguration(config: Config) : NodeConfiguration {
} }
if (networkMapAddress == null) advertisedServices.add(ServiceInfo(NetworkMapService.type)) if (networkMapAddress == null) advertisedServices.add(ServiceInfo(NetworkMapService.type))
val networkMapMessageAddress: SingleMessageRecipient? = if (networkMapAddress == null) null else NodeMessagingClient.makeNetworkMapAddress(networkMapAddress!!) val networkMapMessageAddress: SingleMessageRecipient? = if (networkMapAddress == null) null else NodeMessagingClient.makeNetworkMapAddress(networkMapAddress!!)
return Node(this, networkMapMessageAddress, advertisedServices) return Node(this, networkMapMessageAddress, advertisedServices, if(useTestClock == true) TestClock() else NodeClock())
} }
} }

View File

@ -0,0 +1,43 @@
package com.r3corda.node.utilities
import com.r3corda.core.serialization.SerializeAsToken
import com.r3corda.core.serialization.SerializeAsTokenContext
import com.r3corda.core.serialization.SingletonSerializationToken
import java.time.*
import javax.annotation.concurrent.ThreadSafe
/**
* A [Clock] that can have the date advanced for use in demos.
*/
@ThreadSafe
class TestClock(private var delegateClock: Clock = Clock.systemUTC()) : MutableClock(), SerializeAsToken {
private val token = SingletonSerializationToken(this)
override fun toToken(context: SerializeAsTokenContext) = SingletonSerializationToken.registerWithContext(token, this, context)
@Synchronized fun updateDate(date: LocalDate): Boolean {
val currentDate = LocalDate.now(this)
if (currentDate.isBefore(date)) {
// It's ok to increment
delegateClock = Clock.offset(delegateClock, Duration.between(currentDate.atStartOfDay(), date.atStartOfDay()))
notifyMutationObservers()
return true
}
return false
}
@Synchronized override fun instant(): Instant {
return delegateClock.instant()
}
// Do not use this. Instead seek to use ZonedDateTime methods.
override fun withZone(zone: ZoneId): Clock {
throw UnsupportedOperationException("Tokenized clock does not support withZone()")
}
@Synchronized override fun getZone(): ZoneId {
return delegateClock.zone
}
}

View File

@ -13,4 +13,5 @@ dataSourceProperties = {
devMode = true devMode = true
certificateSigningService = "https://cordaci-netperm.corda.r3cev.com" certificateSigningService = "https://cordaci-netperm.corda.r3cev.com"
useHTTPS = false useHTTPS = false
h2port = 0 h2port = 0
useTestClock = false