From f744c4455e0f0cbd78ae45136e9d4264ab88b1e4 Mon Sep 17 00:00:00 2001 From: Andras Slemmer Date: Fri, 5 May 2017 15:10:56 +0100 Subject: [PATCH] #592: Fix test port allocation flakiness --- .../main/kotlin/net/corda/testing/CoreTestUtils.kt | 12 +++++------- .../src/main/kotlin/net/corda/testing/RPCDriver.kt | 11 ++++++++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt index 7d9a351605..aff00f26c8 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/CoreTestUtils.kt @@ -35,6 +35,7 @@ import java.nio.file.Path import java.security.KeyPair import java.security.PublicKey import java.util.* +import java.util.concurrent.atomic.AtomicInteger import kotlin.reflect.KClass /** @@ -90,6 +91,7 @@ val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Ve fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0) +private val freePortCounter = AtomicInteger(30000) /** * Returns a free port. * @@ -97,7 +99,7 @@ fun generateStateRef() = StateRef(SecureHash.randomSHA256(), 0) * Use [getFreeLocalPorts] for getting multiple ports. */ fun freeLocalHostAndPort(): HostAndPort { - val freePort = ServerSocket(0).use { it.localPort } + val freePort = freePortCounter.getAndAccumulate(0) { prev, _ -> 30000 + (prev - 30000 + 1) % 10000 } return HostAndPort.fromParts("localhost", freePort) } @@ -108,12 +110,8 @@ fun freeLocalHostAndPort(): HostAndPort { * to the Node, some other process else could allocate the returned ports. */ fun getFreeLocalPorts(hostName: String, numberToAlloc: Int): List { - // Create a bunch of sockets up front. - val sockets = Array(numberToAlloc) { ServerSocket(0) } - val result = sockets.map { HostAndPort.fromParts(hostName, it.localPort) } - // Close sockets only once we've grabbed all the ports we need. - sockets.forEach(ServerSocket::close) - return result + val freePort = freePortCounter.getAndAccumulate(0) { prev, _ -> 30000 + (prev - 30000 + numberToAlloc) % 10000 } + return (freePort .. freePort + numberToAlloc - 1).map { HostAndPort.fromParts(hostName, it) } } /** diff --git a/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt b/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt index 8e3ae09eb4..983cfd848e 100644 --- a/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt +++ b/test-utils/src/main/kotlin/net/corda/testing/RPCDriver.kt @@ -10,6 +10,7 @@ import net.corda.client.rpc.internal.RPCClient import net.corda.client.rpc.internal.RPCClientConfiguration import net.corda.core.div import net.corda.core.messaging.RPCOps +import net.corda.core.random63BitValue import net.corda.core.utilities.ProcessUtilities import net.corda.node.driver.* import net.corda.node.services.RPCUserService @@ -101,7 +102,7 @@ interface RPCDriverExposedDSLInterface : DriverDSLExposedInterface { * @param ops The server-side implementation of the RPC interface. */ fun startRpcServer( - serverName: String = "driver-rpc-server", + serverName: String = "driver-rpc-server-${random63BitValue()}", rpcUser: User = rpcTestUser, nodeLegalName: X500Name = fakeNodeLegalName, maxFileSize: Int = ArtemisMessagingServer.MAX_FILE_SIZE, @@ -182,11 +183,14 @@ data class RpcServerHandle( val rpcTestUser = User("user1", "test", permissions = emptySet()) val fakeNodeLegalName = X500Name("not:a:valid:name") +// Use a global pool so that we can run RPC tests in parallel +private val globalPortAllocation = PortAllocation.Incremental(10000) +private val globalDebugPortAllocation = PortAllocation.Incremental(5005) fun rpcDriver( isDebug: Boolean = false, driverDirectory: Path = Paths.get("build", getTimestampAsDirectoryName()), - portAllocation: PortAllocation = PortAllocation.Incremental(10000), - debugPortAllocation: PortAllocation = PortAllocation.Incremental(5005), + portAllocation: PortAllocation = globalPortAllocation, + debugPortAllocation: PortAllocation = globalDebugPortAllocation, systemProperties: Map = emptyMap(), useTestClock: Boolean = false, automaticallyStartNetworkMap: Boolean = false, @@ -339,6 +343,7 @@ data class RPCDriverDSL( ops: I ): ListenableFuture { val hostAndPort = driverDSL.portAllocation.nextHostAndPort() + addressMustNotBeBound(driverDSL.executorService, hostAndPort) return driverDSL.executorService.submit { val artemisConfig = createRpcServerArtemisConfig(maxFileSize, maxBufferedBytesPerClient, driverDSL.driverDirectory / serverName, hostAndPort) val server = ActiveMQServerImpl(artemisConfig, SingleUserSecurityManager(rpcUser))