diff --git a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt index ef83ab852c..683ddbcc0b 100644 --- a/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt +++ b/node/src/test/kotlin/net/corda/node/CordaRPCOpsImplTest.kt @@ -1,5 +1,6 @@ package net.corda.node +import co.paralleluniverse.fibers.Fiber import co.paralleluniverse.fibers.Suspendable import net.corda.client.rpc.PermissionException import net.corda.core.context.AuthServiceId @@ -19,6 +20,7 @@ import net.corda.core.node.services.queryBy import net.corda.core.transactions.SignedTransaction import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.getOrThrow +import net.corda.core.utilities.unwrap import net.corda.finance.DOLLARS import net.corda.finance.GBP import net.corda.finance.USD @@ -43,6 +45,7 @@ import net.corda.testing.node.internal.InternalMockNetwork.MockNode import net.corda.testing.node.internal.InternalMockNodeParameters import net.corda.testing.node.testActor import org.apache.commons.io.IOUtils +import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThatExceptionOfType import org.junit.After import org.junit.Assert.assertArrayEquals @@ -293,6 +296,71 @@ class CordaRPCOpsImplTest { } } + @Test + fun `kill a stuck flow through RPC`() { + + withPermissions(startFlow(), invokeRpc(CordaRPCOps::killFlow), invokeRpc(CordaRPCOps::stateMachinesFeed), invokeRpc(CordaRPCOps::stateMachinesSnapshot)) { + + val flow = rpc.startFlow(::NewJoinerFlow) + + val killed = rpc.killFlow(flow.id) + + assertThat(killed).isTrue() + assertThat(rpc.stateMachinesSnapshot().map { info -> info.id }).doesNotContain(flow.id) + } + } + + @Test + fun `kill a waiting flow through RPC`() { + + withPermissions(startFlow(), invokeRpc(CordaRPCOps::killFlow), invokeRpc(CordaRPCOps::stateMachinesFeed), invokeRpc(CordaRPCOps::stateMachinesSnapshot)) { + + val flow = rpc.startFlow(::HopefulFlow, alice) + + val killed = rpc.killFlow(flow.id) + + assertThat(killed).isTrue() + assertThat(rpc.stateMachinesSnapshot().map { info -> info.id }).doesNotContain(flow.id) + } + } + + @Test + fun `kill a nonexistent flow through RPC`() { + + withPermissions(invokeRpc(CordaRPCOps::killFlow)) { + + val nonexistentFlowId = StateMachineRunId.createRandom() + + val killed = rpc.killFlow(nonexistentFlowId) + + assertThat(killed).isFalse() + } + } + + @StartableByRPC + class NewJoinerFlow : FlowLogic() { + + @Suspendable + override fun call(): String { + + logger.info("When can I join you say? Almost there buddy...") + Fiber.currentFiber().join() + return "You'll never get me!" + } + } + + @StartableByRPC + class HopefulFlow(private val party: Party) : FlowLogic() { + + @Suspendable + override fun call(): String { + + logger.info("Waiting for a miracle...") + val miracle = initiateFlow(party).receive().unwrap { it } + return miracle + } + } + class NonRPCFlow : FlowLogic() { @Suspendable override fun call() = Unit