CORDA-1059 - Fix Driver hanging on duplicate node names. (#2574)

* [CORDA-1059]: Fix bug with Driver hanging on duplicate node names.

* [CORDA-1059]: Code review changes.

* [CORDA-1059]: Code review changes.
This commit is contained in:
Michele Sollecito 2018-02-20 19:59:15 +00:00 committed by Katelyn Baker
parent be0758e52f
commit f4a9a055d9
2 changed files with 49 additions and 2 deletions

View File

@ -3,6 +3,7 @@ package net.corda.testing.driver
import net.corda.core.concurrent.CordaFuture
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.CertRole
import net.corda.core.internal.concurrent.transpose
import net.corda.core.internal.div
import net.corda.core.internal.list
import net.corda.core.internal.readLines
@ -14,15 +15,16 @@ import net.corda.testing.node.internal.addressMustBeBound
import net.corda.testing.node.internal.addressMustNotBeBound
import net.corda.testing.node.internal.internalDriver
import net.corda.testing.core.DUMMY_BANK_A_NAME
import net.corda.testing.core.DUMMY_BANK_B_NAME
import net.corda.testing.core.DUMMY_NOTARY_NAME
import net.corda.testing.driver.internal.NodeHandleInternal
import net.corda.testing.http.HttpApi
import net.corda.testing.node.NotarySpec
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.*
import org.json.simple.JSONObject
import org.junit.Test
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import kotlin.streams.toList
class DriverTests {
private companion object {
@ -116,4 +118,39 @@ class DriverTests {
}
assertThat(baseDirectory / "process-id").doesNotExist()
}
@Test
fun `driver rejects multiple nodes with the same name`() {
driver(DriverParameters(startNodesInProcess = true)) {
assertThatThrownBy { listOf(newNode(DUMMY_BANK_A_NAME)(), newNode(DUMMY_BANK_B_NAME)(), newNode(DUMMY_BANK_A_NAME)()).transpose().getOrThrow() }.isInstanceOf(IllegalArgumentException::class.java)
}
}
@Test
fun `driver rejects multiple nodes with the same name parallel`() {
driver(DriverParameters(startNodesInProcess = true)) {
val nodes = listOf(newNode(DUMMY_BANK_A_NAME), newNode(DUMMY_BANK_B_NAME), newNode(DUMMY_BANK_A_NAME))
assertThatThrownBy { nodes.parallelStream().map { it.invoke() }.toList().transpose().getOrThrow() }.isInstanceOf(IllegalArgumentException::class.java)
}
}
@Test
fun `driver allows reusing names of nodes that have been stopped`() {
driver(DriverParameters(startNodesInProcess = true)) {
val nodeA = newNode(DUMMY_BANK_A_NAME)().getOrThrow()
nodeA.stop()
assertThatCode { newNode(DUMMY_BANK_A_NAME)().getOrThrow() }.doesNotThrowAnyException()
}
}
private fun DriverDSL.newNode(name: CordaX500Name) = { startNode(NodeParameters(providedName = name)) }
}

View File

@ -101,6 +101,7 @@ class DriverDSLImpl(
private val cordappPackages = extraCordappPackagesToScan + getCallerPackage()
// Map from a nodes legal name to an observable emitting the number of nodes in its network map.
private val countObservables = mutableMapOf<CordaX500Name, Observable<Int>>()
private val nodeNames = mutableSetOf<CordaX500Name>()
/**
* Future which completes when the network map is available, whether a local one or one from the CZ. This future acts
* as a gate to prevent nodes from starting too early. The value of the future is a [LocalNetworkMap] object, which
@ -186,6 +187,12 @@ class DriverDSLImpl(
val p2pAddress = portAllocation.nextHostAndPort()
// TODO: Derive name from the full picked name, don't just wrap the common name
val name = providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB")
synchronized(nodeNames) {
val wasANewNode = nodeNames.add(name)
if (!wasANewNode) {
throw IllegalArgumentException("Node with name $name is already started or starting.")
}
}
val registrationFuture = if (compatibilityZone?.rootCert != null) {
// We don't need the network map to be available to be able to register the node
startNodeRegistration(name, compatibilityZone.rootCert, compatibilityZone.url)
@ -642,6 +649,9 @@ class DriverDSLImpl(
val onNodeExit: () -> Unit = {
localNetworkMap?.nodeInfosCopier?.removeConfig(baseDirectory)
countObservables.remove(config.corda.myLegalName)
synchronized(nodeNames) {
nodeNames.remove(config.corda.myLegalName)
}
}
val useHTTPS = config.typesafe.run { hasPath("useHTTPS") && getBoolean("useHTTPS") }