mirror of
https://github.com/corda/corda.git
synced 2025-06-17 22:58:19 +00:00
Fix tests that check ports are bound/unbound (#756)
* Specifically, DriverTests and WebserverDriverTests * RPCDriver.startRpcBroker now waits for port to be unbound, as was probably intended * Explicitly drop network map future while ensuring the error is logged
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -84,7 +84,7 @@ crashlytics-build.properties
|
|||||||
docs/virtualenv/
|
docs/virtualenv/
|
||||||
|
|
||||||
# bft-smart
|
# bft-smart
|
||||||
config/currentView
|
**/config/currentView
|
||||||
|
|
||||||
# vim
|
# vim
|
||||||
*.swp
|
*.swp
|
||||||
|
@ -106,6 +106,7 @@ fun <T> ListenableFuture<T>.failure(executor: Executor, body: (Throwable) -> Uni
|
|||||||
infix fun <T> ListenableFuture<T>.then(body: () -> Unit): ListenableFuture<T> = apply { then(RunOnCallerThread, body) }
|
infix fun <T> ListenableFuture<T>.then(body: () -> Unit): ListenableFuture<T> = apply { then(RunOnCallerThread, body) }
|
||||||
infix fun <T> ListenableFuture<T>.success(body: (T) -> Unit): ListenableFuture<T> = apply { success(RunOnCallerThread, body) }
|
infix fun <T> ListenableFuture<T>.success(body: (T) -> Unit): ListenableFuture<T> = apply { success(RunOnCallerThread, body) }
|
||||||
infix fun <T> ListenableFuture<T>.failure(body: (Throwable) -> Unit): ListenableFuture<T> = apply { failure(RunOnCallerThread, body) }
|
infix fun <T> ListenableFuture<T>.failure(body: (Throwable) -> Unit): ListenableFuture<T> = apply { failure(RunOnCallerThread, body) }
|
||||||
|
fun <T> ListenableFuture<T>.andForget(log: Logger) = failure(RunOnCallerThread) { log.error("Background task failed:", it) }
|
||||||
@Suppress("UNCHECKED_CAST") // We need the awkward cast because otherwise F cannot be nullable, even though it's safe.
|
@Suppress("UNCHECKED_CAST") // We need the awkward cast because otherwise F cannot be nullable, even though it's safe.
|
||||||
infix fun <F, T> ListenableFuture<F>.map(mapper: (F) -> T): ListenableFuture<T> = Futures.transform(this, { (mapper as (F?) -> T)(it) })
|
infix fun <F, T> ListenableFuture<F>.map(mapper: (F) -> T): ListenableFuture<T> = Futures.transform(this, { (mapper as (F?) -> T)(it) })
|
||||||
infix fun <F, T> ListenableFuture<F>.flatMap(mapper: (F) -> ListenableFuture<T>): ListenableFuture<T> = Futures.transformAsync(this) { mapper(it!!) }
|
infix fun <F, T> ListenableFuture<F>.flatMap(mapper: (F) -> ListenableFuture<T>): ListenableFuture<T> = Futures.transformAsync(this) { mapper(it!!) }
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
package net.corda.core
|
package net.corda.core
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.MoreExecutors
|
||||||
|
import com.nhaarman.mockito_kotlin.mock
|
||||||
|
import com.nhaarman.mockito_kotlin.same
|
||||||
|
import com.nhaarman.mockito_kotlin.verify
|
||||||
import org.assertj.core.api.Assertions.*
|
import org.assertj.core.api.Assertions.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
import org.mockito.ArgumentMatchers.anyString
|
||||||
|
import org.slf4j.Logger
|
||||||
import rx.subjects.PublishSubject
|
import rx.subjects.PublishSubject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.CancellationException
|
import java.util.concurrent.CancellationException
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class UtilsTest {
|
class UtilsTest {
|
||||||
@Test
|
@Test
|
||||||
@ -57,4 +65,17 @@ class UtilsTest {
|
|||||||
future.get()
|
future.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
|
fun `andForget works`() {
|
||||||
|
val log = mock<Logger>()
|
||||||
|
val throwable = Exception("Boom")
|
||||||
|
val executor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor())
|
||||||
|
executor.submit { throw throwable }.andForget(log)
|
||||||
|
executor.shutdown()
|
||||||
|
while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
verify(log).error(anyString(), same(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -261,7 +261,11 @@ class ListenProcessDeathException(message: String) : Exception(message)
|
|||||||
/**
|
/**
|
||||||
* @throws ListenProcessDeathException if [listenProcess] dies before the check succeeds, i.e. the check can't succeed as intended.
|
* @throws ListenProcessDeathException if [listenProcess] dies before the check succeeds, i.e. the check can't succeed as intended.
|
||||||
*/
|
*/
|
||||||
fun addressMustBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort, listenProcess: Process): ListenableFuture<Unit> {
|
fun addressMustBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort, listenProcess: Process) {
|
||||||
|
addressMustBeBoundFuture(executorService, hostAndPort, listenProcess).getOrThrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addressMustBeBoundFuture(executorService: ScheduledExecutorService, hostAndPort: HostAndPort, listenProcess: Process): ListenableFuture<Unit> {
|
||||||
return poll(executorService, "address $hostAndPort to bind") {
|
return poll(executorService, "address $hostAndPort to bind") {
|
||||||
if (!listenProcess.isAlive) {
|
if (!listenProcess.isAlive) {
|
||||||
throw ListenProcessDeathException("The process that was expected to listen on $hostAndPort has died with status: ${listenProcess.exitValue()}")
|
throw ListenProcessDeathException("The process that was expected to listen on $hostAndPort has died with status: ${listenProcess.exitValue()}")
|
||||||
@ -275,7 +279,11 @@ fun addressMustBeBound(executorService: ScheduledExecutorService, hostAndPort: H
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addressMustNotBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort): ListenableFuture<Unit> {
|
fun addressMustNotBeBound(executorService: ScheduledExecutorService, hostAndPort: HostAndPort) {
|
||||||
|
addressMustNotBeBoundFuture(executorService, hostAndPort).getOrThrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addressMustNotBeBoundFuture(executorService: ScheduledExecutorService, hostAndPort: HostAndPort): ListenableFuture<Unit> {
|
||||||
return poll(executorService, "address $hostAndPort to unbind") {
|
return poll(executorService, "address $hostAndPort to unbind") {
|
||||||
try {
|
try {
|
||||||
Socket(hostAndPort.host, hostAndPort.port).close()
|
Socket(hostAndPort.host, hostAndPort.port).close()
|
||||||
@ -608,7 +616,7 @@ class DriverDSL(
|
|||||||
)
|
)
|
||||||
_shutdownManager = ShutdownManager(executorService)
|
_shutdownManager = ShutdownManager(executorService)
|
||||||
if (networkMapStartStrategy.startDedicated) {
|
if (networkMapStartStrategy.startDedicated) {
|
||||||
startDedicatedNetworkMapService()
|
startDedicatedNetworkMapService().andForget(log) // Allow it to start concurrently with other nodes.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,7 +642,7 @@ class DriverDSL(
|
|||||||
log.info("Starting network-map-service")
|
log.info("Starting network-map-service")
|
||||||
val startNode = startNode(executorService, config.parseAs<FullNodeConfiguration>(), config, quasarJarPath, debugPort, systemProperties)
|
val startNode = startNode(executorService, config.parseAs<FullNodeConfiguration>(), config, quasarJarPath, debugPort, systemProperties)
|
||||||
registerProcess(startNode)
|
registerProcess(startNode)
|
||||||
return startNode.flatMap { addressMustBeBound(executorService, dedicatedNetworkMapAddress, it) }
|
return startNode.flatMap { addressMustBeBoundFuture(executorService, dedicatedNetworkMapAddress, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <A> pollUntilNonNull(pollName: String, pollInterval: Duration, warnCount: Int, check: () -> A?): ListenableFuture<A> {
|
override fun <A> pollUntilNonNull(pollName: String, pollInterval: Duration, warnCount: Int, check: () -> A?): ListenableFuture<A> {
|
||||||
@ -693,7 +701,7 @@ class DriverDSL(
|
|||||||
errorLogPath = nodeConf.baseDirectory / LOGS_DIRECTORY_NAME / "error.log",
|
errorLogPath = nodeConf.baseDirectory / LOGS_DIRECTORY_NAME / "error.log",
|
||||||
workingDirectory = nodeConf.baseDirectory
|
workingDirectory = nodeConf.baseDirectory
|
||||||
)
|
)
|
||||||
}.flatMap { process -> addressMustBeBound(executorService, nodeConf.p2pAddress, process).map { process } }
|
}.flatMap { process -> addressMustBeBoundFuture(executorService, nodeConf.p2pAddress, process).map { process } }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startWebserver(
|
private fun startWebserver(
|
||||||
@ -713,7 +721,7 @@ class DriverDSL(
|
|||||||
),
|
),
|
||||||
errorLogPath = Paths.get("error.$className.log")
|
errorLogPath = Paths.get("error.$className.log")
|
||||||
)
|
)
|
||||||
}.flatMap { process -> addressMustBeBound(executorService, handle.webAddress, process).map { process } }
|
}.flatMap { process -> addressMustBeBoundFuture(executorService, handle.webAddress, process).map { process } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,7 @@ data class RPCDriverDSL(
|
|||||||
server.start()
|
server.start()
|
||||||
driverDSL.shutdownManager.registerShutdown {
|
driverDSL.shutdownManager.registerShutdown {
|
||||||
server.stop()
|
server.stop()
|
||||||
addressMustNotBeBound(driverDSL.executorService, hostAndPort).get()
|
addressMustNotBeBound(driverDSL.executorService, hostAndPort)
|
||||||
}
|
}
|
||||||
RpcBrokerHandle(
|
RpcBrokerHandle(
|
||||||
hostAndPort = hostAndPort,
|
hostAndPort = hostAndPort,
|
||||||
|
@ -11,7 +11,7 @@ import net.corda.core.node.services.ServiceType
|
|||||||
import net.corda.core.utilities.DUMMY_CA
|
import net.corda.core.utilities.DUMMY_CA
|
||||||
import net.corda.core.utilities.DUMMY_MAP
|
import net.corda.core.utilities.DUMMY_MAP
|
||||||
import net.corda.core.utilities.WHITESPACE
|
import net.corda.core.utilities.WHITESPACE
|
||||||
import net.corda.node.driver.addressMustNotBeBound
|
import net.corda.node.driver.addressMustNotBeBoundFuture
|
||||||
import net.corda.node.internal.Node
|
import net.corda.node.internal.Node
|
||||||
import net.corda.node.services.config.ConfigHelper
|
import net.corda.node.services.config.ConfigHelper
|
||||||
import net.corda.node.services.config.FullNodeConfiguration
|
import net.corda.node.services.config.FullNodeConfiguration
|
||||||
@ -62,8 +62,8 @@ abstract class NodeBasedTest {
|
|||||||
// Wait until ports are released
|
// Wait until ports are released
|
||||||
val portNotBoundChecks = nodes.flatMap {
|
val portNotBoundChecks = nodes.flatMap {
|
||||||
listOf(
|
listOf(
|
||||||
it.configuration.p2pAddress.let { addressMustNotBeBound(shutdownExecutor, it) },
|
it.configuration.p2pAddress.let { addressMustNotBeBoundFuture(shutdownExecutor, it) },
|
||||||
it.configuration.rpcAddress?.let { addressMustNotBeBound(shutdownExecutor, it) }
|
it.configuration.rpcAddress?.let { addressMustNotBeBoundFuture(shutdownExecutor, it) }
|
||||||
)
|
)
|
||||||
}.filterNotNull()
|
}.filterNotNull()
|
||||||
nodes.clear()
|
nodes.clear()
|
||||||
|
Reference in New Issue
Block a user