mirror of
https://github.com/corda/corda.git
synced 2025-06-21 08:40:03 +00:00
CORDA-1099: Orchestrated clean shutdown from Shell (#2831)
This commit is contained in:
committed by
GitHub
parent
c964e50696
commit
7a077e76f0
@ -18,28 +18,28 @@ import net.corda.finance.flows.CashPaymentFlow
|
||||
import net.corda.finance.schemas.CashSchemaV1
|
||||
import net.corda.node.internal.Node
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.Permissions.Companion.invokeRpc
|
||||
import net.corda.node.services.Permissions.Companion.startFlow
|
||||
import net.corda.node.services.Permissions.Companion.all
|
||||
import net.corda.testing.core.*
|
||||
import net.corda.testing.node.User
|
||||
import net.corda.testing.node.internal.NodeBasedTest
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQNotConnectedException
|
||||
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import rx.subjects.PublishSubject
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledExecutorService
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", CashSchemaV1::class.packageName)) {
|
||||
private val rpcUser = User("user1", "test", permissions = setOf(
|
||||
startFlow<CashIssueFlow>(),
|
||||
startFlow<CashPaymentFlow>(),
|
||||
invokeRpc("vaultQueryBy"),
|
||||
invokeRpc(CordaRPCOps::stateMachinesFeed),
|
||||
invokeRpc("vaultQueryByCriteria"))
|
||||
private val rpcUser = User("user1", "test", permissions = setOf(all())
|
||||
)
|
||||
private lateinit var node: StartedNode<Node>
|
||||
private lateinit var identity: Party
|
||||
@ -53,7 +53,9 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
|
||||
@Before
|
||||
fun setUp() {
|
||||
node = startNode(ALICE_NAME, rpcUsers = listOf(rpcUser))
|
||||
client = CordaRPCClient(node.internals.configuration.rpcOptions.address!!)
|
||||
client = CordaRPCClient(node.internals.configuration.rpcOptions.address!!, object : CordaRPCClientConfiguration {
|
||||
override val maxReconnectAttempts = 5
|
||||
})
|
||||
identity = node.info.identityFromX500Name(ALICE_NAME)
|
||||
}
|
||||
|
||||
@ -81,6 +83,61 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `shutdown command stops the node`() {
|
||||
|
||||
val nodeIsShut: PublishSubject<Unit> = PublishSubject.create()
|
||||
val latch = CountDownLatch(1)
|
||||
var successful = false
|
||||
val maxCount = 20
|
||||
var count = 0
|
||||
CloseableExecutor(Executors.newSingleThreadScheduledExecutor()).use { scheduler ->
|
||||
|
||||
val task = scheduler.scheduleAtFixedRate({
|
||||
try {
|
||||
println("Checking whether node is still running...")
|
||||
client.start(rpcUser.username, rpcUser.password).use {
|
||||
println("... node is still running.")
|
||||
if (count == maxCount) {
|
||||
nodeIsShut.onError(AssertionError("Node does not get shutdown by RPC"))
|
||||
}
|
||||
count++
|
||||
}
|
||||
} catch (e: ActiveMQNotConnectedException) {
|
||||
println("... node is not running.")
|
||||
nodeIsShut.onCompleted()
|
||||
} catch (e: ActiveMQSecurityException) {
|
||||
// nothing here - this happens if trying to connect before the node is started
|
||||
} catch (e: Throwable) {
|
||||
nodeIsShut.onError(e)
|
||||
}
|
||||
}, 1, 1, TimeUnit.SECONDS)
|
||||
|
||||
nodeIsShut.doOnError { error ->
|
||||
error.printStackTrace()
|
||||
successful = false
|
||||
task.cancel(true)
|
||||
latch.countDown()
|
||||
}.doOnCompleted {
|
||||
successful = (node.internals.started == null)
|
||||
task.cancel(true)
|
||||
latch.countDown()
|
||||
}.subscribe()
|
||||
|
||||
client.start(rpcUser.username, rpcUser.password).use { rpc -> rpc.proxy.shutdown() }
|
||||
|
||||
latch.await()
|
||||
assertThat(successful).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
private class CloseableExecutor(private val delegate: ScheduledExecutorService) : AutoCloseable, ScheduledExecutorService by delegate {
|
||||
|
||||
override fun close() {
|
||||
delegate.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `close-send deadlock and premature shutdown on empty observable`() {
|
||||
println("Starting client")
|
||||
@ -141,7 +198,7 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
|
||||
|
||||
val updates = proxy.stateMachinesFeed().updates
|
||||
|
||||
node.services.startFlow(CashIssueFlow(2000.DOLLARS, OpaqueBytes.of(0),identity), InvocationContext.shell()).flatMap { it.resultFuture }.getOrThrow()
|
||||
node.services.startFlow(CashIssueFlow(2000.DOLLARS, OpaqueBytes.of(0), identity), InvocationContext.shell()).flatMap { it.resultFuture }.getOrThrow()
|
||||
proxy.startFlow(::CashIssueFlow, 123.DOLLARS, OpaqueBytes.of(0), identity).returnValue.getOrThrow()
|
||||
proxy.startFlowDynamic(CashIssueFlow::class.java, 1000.DOLLARS, OpaqueBytes.of(0), identity).returnValue.getOrThrow()
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.client.rpc
|
||||
|
||||
import net.corda.client.rpc.internal.RPCClient
|
||||
import net.corda.client.rpc.internal.RPCClientConfiguration
|
||||
import net.corda.client.rpc.internal.CordaRPCClientConfigurationImpl
|
||||
import net.corda.core.context.Trace
|
||||
import net.corda.core.crypto.random63BitValue
|
||||
import net.corda.core.internal.concurrent.fork
|
||||
@ -105,7 +105,7 @@ class RPCStabilityTests {
|
||||
Try.on {
|
||||
startRpcClient<RPCOps>(
|
||||
server.get().broker.hostAndPort!!,
|
||||
configuration = RPCClientConfiguration.default.copy(minimumServerProtocolVersion = 1)
|
||||
configuration = CordaRPCClientConfigurationImpl.default.copy(minimumServerProtocolVersion = 1)
|
||||
).get()
|
||||
}
|
||||
}
|
||||
@ -240,7 +240,7 @@ class RPCStabilityTests {
|
||||
val serverPort = startRpcServer<ReconnectOps>(ops = ops).getOrThrow().broker.hostAndPort!!
|
||||
serverFollower.unfollow()
|
||||
// Set retry interval to 1s to reduce test duration
|
||||
val clientConfiguration = RPCClientConfiguration.default.copy(connectionRetryInterval = 1.seconds)
|
||||
val clientConfiguration = CordaRPCClientConfigurationImpl.default.copy(connectionRetryInterval = 1.seconds)
|
||||
val clientFollower = shutdownManager.follower()
|
||||
val client = startRpcClient<ReconnectOps>(serverPort, configuration = clientConfiguration).getOrThrow()
|
||||
clientFollower.unfollow()
|
||||
@ -266,7 +266,7 @@ class RPCStabilityTests {
|
||||
val serverPort = startRpcServer<ReconnectOps>(ops = ops).getOrThrow().broker.hostAndPort!!
|
||||
serverFollower.unfollow()
|
||||
// Set retry interval to 1s to reduce test duration
|
||||
val clientConfiguration = RPCClientConfiguration.default.copy(connectionRetryInterval = 1.seconds, maxReconnectAttempts = 5)
|
||||
val clientConfiguration = CordaRPCClientConfigurationImpl.default.copy(connectionRetryInterval = 1.seconds, maxReconnectAttempts = 5)
|
||||
val clientFollower = shutdownManager.follower()
|
||||
val client = startRpcClient<ReconnectOps>(serverPort, configuration = clientConfiguration).getOrThrow()
|
||||
clientFollower.unfollow()
|
||||
@ -298,7 +298,7 @@ class RPCStabilityTests {
|
||||
val serverPort = startRpcServer<NoOps>(ops = ops).getOrThrow().broker.hostAndPort!!
|
||||
serverFollower.unfollow()
|
||||
|
||||
val clientConfiguration = RPCClientConfiguration.default.copy(connectionRetryInterval = 500.millis, maxReconnectAttempts = 1)
|
||||
val clientConfiguration = CordaRPCClientConfigurationImpl.default.copy(connectionRetryInterval = 500.millis, maxReconnectAttempts = 1)
|
||||
val clientFollower = shutdownManager.follower()
|
||||
val client = startRpcClient<NoOps>(serverPort, configuration = clientConfiguration).getOrThrow()
|
||||
clientFollower.unfollow()
|
||||
|
Reference in New Issue
Block a user