mirror of
https://github.com/corda/corda.git
synced 2025-04-07 11:27:01 +00:00
[CORDA-2278]: KillFlow RPC operation is not releasing soft locks. (#4332)
* [CORDA-2278]: Seems to be working. Leaving the test to ensure no future regressions. * [CORDA-2278]: Seems to be working. Leaving the test to ensure no future regressions. * [CORDA-2278]: Seems to be working. Leaving the test to ensure no future regressions. * [CORDA-2278]: Seems to be working. Leaving the test to ensure no future regressions.
This commit is contained in:
parent
3444d6c075
commit
a9ff8a0818
@ -8,6 +8,7 @@ import net.corda.core.context.InvocationContext
|
||||
import net.corda.core.contracts.Amount
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.contracts.Issued
|
||||
import net.corda.core.contracts.StateRef
|
||||
import net.corda.core.crypto.isFulfilledBy
|
||||
import net.corda.core.crypto.keys
|
||||
import net.corda.core.flows.FlowLogic
|
||||
@ -16,12 +17,14 @@ import net.corda.core.flows.StateMachineRunId
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.messaging.*
|
||||
import net.corda.core.node.services.StatesNotAvailableException
|
||||
import net.corda.core.node.services.Vault
|
||||
import net.corda.core.node.services.queryBy
|
||||
import net.corda.core.node.services.vault.AttachmentQueryCriteria
|
||||
import net.corda.core.node.services.vault.ColumnPredicate
|
||||
import net.corda.core.node.services.vault.EqualityComparisonOperator
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.utilities.NonEmptySet
|
||||
import net.corda.core.utilities.OpaqueBytes
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import net.corda.core.utilities.unwrap
|
||||
@ -32,6 +35,7 @@ import net.corda.finance.flows.CashIssueFlow
|
||||
import net.corda.finance.flows.CashPaymentFlow
|
||||
import net.corda.node.internal.security.AuthorizingSubject
|
||||
import net.corda.node.internal.security.RPCSecurityManagerImpl
|
||||
import net.corda.node.services.Permissions.Companion.all
|
||||
import net.corda.node.services.Permissions.Companion.invokeRpc
|
||||
import net.corda.node.services.Permissions.Companion.startFlow
|
||||
import net.corda.node.services.messaging.CURRENT_RPC_CONTEXT
|
||||
@ -56,6 +60,7 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import rx.Observable
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.time.Duration
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
@ -385,6 +390,39 @@ class CordaRPCOpsImplTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `killing a flow releases soft lock`() {
|
||||
withPermissions(all()) {
|
||||
val issuerRef = OpaqueBytes("BankOfMars".toByteArray())
|
||||
val cash = rpc.startFlow(::CashIssueFlow, 10.DOLLARS, issuerRef, notary).returnValue.getOrThrow().stx.tx.outRefsOfType<Cash.State>().single()
|
||||
|
||||
val flow = rpc.startFlow(::SoftLock, cash.ref, Duration.ofMinutes(5))
|
||||
|
||||
var locked = false
|
||||
while (!locked) {
|
||||
try {
|
||||
rpc.startFlow(::SoftLock, cash.ref, Duration.ofSeconds(1)).returnValue.getOrThrow()
|
||||
} catch (e: StatesNotAvailableException) {
|
||||
locked = true
|
||||
}
|
||||
}
|
||||
|
||||
val killed = rpc.killFlow(flow.id)
|
||||
assertThat(killed).isTrue()
|
||||
assertThatCode { rpc.startFlow(::SoftLock, cash.ref, Duration.ofSeconds(1)).returnValue.getOrThrow() }.doesNotThrowAnyException()
|
||||
}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class SoftLock(private val stateRef: StateRef, private val duration: Duration) : FlowLogic<Unit>() {
|
||||
@Suspendable
|
||||
override fun call() {
|
||||
logger.info("Soft locking state with hash $stateRef...")
|
||||
serviceHub.vaultService.softLockReserve(runId.uuid, NonEmptySet.of(stateRef))
|
||||
sleep(duration)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `kill a nonexistent flow through RPC`() {
|
||||
withPermissions(invokeRpc(CordaRPCOps::killFlow)) {
|
||||
|
@ -5,6 +5,14 @@ apply plugin: 'com.jfrog.artifactory'
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':node-api')
|
||||
|
||||
// Unit testing helpers.
|
||||
compile "junit:junit:$junit_version"
|
||||
compile 'org.hamcrest:hamcrest-library:1.3'
|
||||
compile "com.nhaarman:mockito-kotlin:$mockito_kotlin_version"
|
||||
compile "org.mockito:mockito-core:$mockito_version"
|
||||
compile "org.assertj:assertj-core:$assertj_version"
|
||||
compile "com.natpryce:hamkrest:$hamkrest_version"
|
||||
}
|
||||
|
||||
jar {
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.corda.testing.common.internal
|
||||
|
||||
import org.assertj.core.api.AbstractThrowableAssert
|
||||
|
||||
inline fun checkNotOnClasspath(className: String, errorMessage: () -> Any) {
|
||||
try {
|
||||
Class.forName(className)
|
||||
@ -8,3 +10,5 @@ inline fun checkNotOnClasspath(className: String, errorMessage: () -> Any) {
|
||||
// If the class can't be found then we're good!
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified TYPE : Throwable> AbstractThrowableAssert<*, *>.isInstanceOf(): AbstractThrowableAssert<*, *> = isInstanceOf(TYPE::class.java)
|
||||
|
@ -21,14 +21,6 @@ dependencies {
|
||||
|
||||
compile "com.google.guava:guava:$guava_version"
|
||||
|
||||
// Unit testing helpers.
|
||||
compile "junit:junit:$junit_version"
|
||||
compile 'org.hamcrest:hamcrest-library:1.3'
|
||||
compile "com.nhaarman:mockito-kotlin:$mockito_kotlin_version"
|
||||
compile "org.mockito:mockito-core:$mockito_version"
|
||||
compile "org.assertj:assertj-core:$assertj_version"
|
||||
compile "com.natpryce:hamkrest:$hamkrest_version"
|
||||
|
||||
// Guava: Google test library (collections test suite)
|
||||
compile "com.google.guava:guava-testlib:$guava_version"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user