mirror of
https://github.com/corda/corda.git
synced 2025-01-18 02:39:51 +00:00
Renaming matchers
This commit is contained in:
parent
0780d6051e
commit
fc5cc89fdb
@ -5,8 +5,8 @@ import com.natpryce.hamkrest.*
|
||||
import com.natpryce.hamkrest.assertion.assert
|
||||
import net.corda.core.contracts.Attachment
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.flows.matchers.fails
|
||||
import net.corda.core.flows.matchers.succeedsWith
|
||||
import net.corda.core.flows.matchers.flow.willThrow
|
||||
import net.corda.core.flows.matchers.flow.willReturn
|
||||
import net.corda.core.flows.mixins.WithMockNet
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
@ -51,7 +51,7 @@ class AttachmentTests : WithMockNet {
|
||||
// Get node one to run a flow to fetch it and insert it.
|
||||
assert.that(
|
||||
bobNode.startAttachmentFlow(id, alice),
|
||||
succeedsWith(noAttachments()))
|
||||
willReturn(noAttachments()))
|
||||
|
||||
// Verify it was inserted into node one's store.
|
||||
val attachment = bobNode.getAttachmentWithId(id)
|
||||
@ -62,7 +62,7 @@ class AttachmentTests : WithMockNet {
|
||||
|
||||
assert.that(
|
||||
bobNode.startAttachmentFlow(id, alice),
|
||||
succeedsWith(soleAttachment(attachment)))
|
||||
willReturn(soleAttachment(attachment)))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -72,10 +72,14 @@ class AttachmentTests : WithMockNet {
|
||||
// Get node one to fetch a non-existent attachment.
|
||||
assert.that(
|
||||
bobNode.startAttachmentFlow(hash, alice),
|
||||
fails<FetchDataFlow.HashNotFound>(
|
||||
has("requested hash", { it.requested }, equalTo(hash))))
|
||||
willThrow(withRequestedHash(hash)))
|
||||
}
|
||||
|
||||
fun withRequestedHash(expected: SecureHash) = has(
|
||||
"requested hash",
|
||||
FetchDataFlow.HashNotFound::requested,
|
||||
equalTo(expected))
|
||||
|
||||
@Test
|
||||
fun maliciousResponse() {
|
||||
// Make a node that doesn't do sanity checking at load time.
|
||||
@ -96,7 +100,7 @@ class AttachmentTests : WithMockNet {
|
||||
// Get n1 to fetch the attachment. Should receive corrupted bytes.
|
||||
assert.that(
|
||||
bobNode.startAttachmentFlow(id, badAlice),
|
||||
fails<FetchDataFlow.DownloadedVsRequestedDataMismatch>()
|
||||
willThrow<FetchDataFlow.DownloadedVsRequestedDataMismatch>()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,8 @@ import com.natpryce.hamkrest.assertion.assert
|
||||
import net.corda.core.contracts.Command
|
||||
import net.corda.core.contracts.StateAndContract
|
||||
import net.corda.core.contracts.requireThat
|
||||
import net.corda.core.flows.matchers.fails
|
||||
import net.corda.core.flows.matchers.succeedsWith
|
||||
import net.corda.core.flows.matchers.flow.willThrow
|
||||
import net.corda.core.flows.matchers.flow.willReturn
|
||||
import net.corda.core.flows.mixins.WithContracts
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
@ -28,6 +28,7 @@ class CollectSignaturesFlowTests : WithContracts {
|
||||
private val miniCorp = TestIdentity(CordaX500Name("MiniCorp", "London", "GB"))
|
||||
private val miniCorpServices = MockServices(listOf("net.corda.testing.contracts"), miniCorp, rigorousMock())
|
||||
private val classMockNet = InternalMockNetwork(cordappPackages = listOf("net.corda.testing.contracts", "net.corda.core.flows"))
|
||||
|
||||
private const val MAGIC_NUMBER = 1337
|
||||
|
||||
@JvmStatic
|
||||
@ -35,7 +36,6 @@ class CollectSignaturesFlowTests : WithContracts {
|
||||
fun tearDown() = classMockNet.stopNodes()
|
||||
}
|
||||
|
||||
override val magicNumber = MAGIC_NUMBER
|
||||
override val mockNet = classMockNet
|
||||
|
||||
private val aliceNode = makeNode(ALICE_NAME)
|
||||
@ -53,7 +53,7 @@ class CollectSignaturesFlowTests : WithContracts {
|
||||
|
||||
assert.that(
|
||||
aliceNode.startTestFlow(alice, bConfidentialIdentity.party, charlie),
|
||||
succeedsWith(requiredSignatures(3))
|
||||
willReturn(requiredSignatures(3))
|
||||
)
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ class CollectSignaturesFlowTests : WithContracts {
|
||||
|
||||
assert.that(
|
||||
aliceNode.collectSignatures(ptx),
|
||||
succeedsWith(requiredSignatures(1))
|
||||
willReturn(requiredSignatures(1))
|
||||
)
|
||||
}
|
||||
|
||||
@ -73,20 +73,21 @@ class CollectSignaturesFlowTests : WithContracts {
|
||||
|
||||
assert.that(
|
||||
aliceNode.collectSignatures(ptx),
|
||||
fails(errorMessage("The Initiator of CollectSignaturesFlow must have signed the transaction.")))
|
||||
willThrow(errorMessage("The Initiator of CollectSignaturesFlow must have signed the transaction.")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `passes with multiple initial signatures`() {
|
||||
val signedByA = aliceNode.signDummyContract(
|
||||
alice.ref(1),
|
||||
MAGIC_NUMBER,
|
||||
bob.ref(2),
|
||||
bob.ref(3))
|
||||
val signedByBoth = bobNode.addSignatureTo(signedByA)
|
||||
|
||||
assert.that(
|
||||
aliceNode.collectSignatures(signedByBoth),
|
||||
succeedsWith(requiredSignatures(2))
|
||||
willReturn(requiredSignatures(2))
|
||||
)
|
||||
}
|
||||
|
||||
@ -94,7 +95,7 @@ class CollectSignaturesFlowTests : WithContracts {
|
||||
private fun StartedNode<*>.startTestFlow(vararg party: Party) =
|
||||
startFlow(
|
||||
TestFlow.Initiator(DummyContract.MultiOwnerState(
|
||||
magicNumber,
|
||||
MAGIC_NUMBER,
|
||||
listOf(*party)),
|
||||
mockNet.defaultNotaryIdentity))
|
||||
.andRunNetwork()
|
||||
|
@ -0,0 +1,144 @@
|
||||
package net.corda.core.flows
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.natpryce.hamkrest.*
|
||||
import com.natpryce.hamkrest.assertion.assert
|
||||
import net.corda.core.CordaRuntimeException
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.flows.matchers.rpc.willThrow
|
||||
import net.corda.core.flows.matchers.rpc.willReturn
|
||||
import net.corda.core.flows.mixins.WithContracts
|
||||
import net.corda.core.flows.mixins.WithFinality
|
||||
import net.corda.core.identity.AbstractParty
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.internal.Emoji
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.transactions.ContractUpgradeLedgerTransaction
|
||||
import net.corda.core.transactions.LedgerTransaction
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.finance.contracts.asset.Cash
|
||||
import net.corda.node.internal.StartedNode
|
||||
import net.corda.node.services.Permissions.Companion.startFlow
|
||||
import net.corda.testing.contracts.DummyContract
|
||||
import net.corda.testing.contracts.DummyContractV2
|
||||
import net.corda.testing.core.ALICE_NAME
|
||||
import net.corda.testing.core.BOB_NAME
|
||||
import net.corda.testing.core.singleIdentity
|
||||
import net.corda.testing.node.User
|
||||
import net.corda.testing.node.internal.*
|
||||
import net.corda.testing.node.internal.InternalMockNetwork.MockNode
|
||||
import org.junit.AfterClass
|
||||
import org.junit.Test
|
||||
|
||||
class ContractUpgradeFlowRPCTest : WithContracts, WithFinality {
|
||||
companion object {
|
||||
private val classMockNet = InternalMockNetwork(cordappPackages = listOf(
|
||||
"net.corda.testing.contracts",
|
||||
"net.corda.finance.contracts.asset",
|
||||
"net.corda.core.flows"))
|
||||
|
||||
@JvmStatic
|
||||
@AfterClass
|
||||
fun tearDown() = classMockNet.stopNodes()
|
||||
}
|
||||
|
||||
override val mockNet = classMockNet
|
||||
|
||||
private val aliceNode = makeNode(ALICE_NAME)
|
||||
private val bobNode = makeNode(BOB_NAME)
|
||||
|
||||
private val alice = aliceNode.info.singleIdentity()
|
||||
private val bob = bobNode.info.singleIdentity()
|
||||
|
||||
@Test
|
||||
fun `2 parties contract upgrade using RPC`() = rpcDriver {
|
||||
val testUser = createTestUser()
|
||||
val rpcA = startProxy(aliceNode, testUser)
|
||||
val rpcB = startProxy(bobNode, testUser)
|
||||
|
||||
// Create, sign and finalise dummy contract.
|
||||
val signedByA = aliceNode.signDummyContract(alice.ref(1), 0, bob.ref(1))
|
||||
val stx = bobNode.addSignatureTo(signedByA)
|
||||
assert.that(rpcA.finalise(stx, bob), willReturn())
|
||||
|
||||
val atx = aliceNode.getValidatedTransaction(stx)
|
||||
val btx = bobNode.getValidatedTransaction(stx)
|
||||
|
||||
// Cannot upgrade contract without prior authorisation from counterparty
|
||||
assert.that(
|
||||
rpcA.initiateDummyContractUpgrade(atx),
|
||||
willThrow<CordaRuntimeException>())
|
||||
|
||||
// Party B authorises the contract state upgrade, and immediately deauthorises the same.
|
||||
assert.that(rpcB.authoriseDummyContractUpgrade(btx), willReturn())
|
||||
assert.that(rpcB.deauthoriseContractUpgrade(btx), willReturn())
|
||||
|
||||
// Cannot upgrade contract if counterparty has deauthorised a previously-given authority
|
||||
assert.that(
|
||||
rpcA.initiateDummyContractUpgrade(atx),
|
||||
willThrow<CordaRuntimeException>())
|
||||
|
||||
// Party B authorise the contract state upgrade.
|
||||
assert.that(rpcB.authoriseDummyContractUpgrade(btx), willReturn())
|
||||
|
||||
// Party A initiates contract upgrade flow, expected to succeed this time.
|
||||
assert.that(
|
||||
rpcA.initiateDummyContractUpgrade(atx),
|
||||
willReturn(
|
||||
aliceNode.hasDummyContractUpgradeTransaction()
|
||||
and bobNode.hasDummyContractUpgradeTransaction()))
|
||||
}
|
||||
|
||||
//region RPC DSL
|
||||
private fun RPCDriverDSL.startProxy(node: StartedNode<MockNode>, user: User): CordaRPCOps {
|
||||
return startRpcClient<CordaRPCOps>(
|
||||
rpcAddress = startRpcServer(
|
||||
rpcUser = user,
|
||||
ops = node.rpcOps
|
||||
).get().broker.hostAndPort!!,
|
||||
username = user.username,
|
||||
password = user.password
|
||||
).get()
|
||||
}
|
||||
|
||||
private fun RPCDriverDSL.createTestUser() = rpcTestUser.copy(permissions = setOf(
|
||||
startFlow<WithFinality.FinalityInvoker>(),
|
||||
startFlow<ContractUpgradeFlow.Initiate<*, *>>(),
|
||||
startFlow<ContractUpgradeFlow.Authorise>(),
|
||||
startFlow<ContractUpgradeFlow.Deauthorise>()
|
||||
))
|
||||
//endregion
|
||||
|
||||
//region Operations
|
||||
private fun CordaRPCOps.initiateDummyContractUpgrade(tx: SignedTransaction) =
|
||||
initiateContractUpgrade(tx, DummyContractV2::class)
|
||||
|
||||
private fun CordaRPCOps.authoriseDummyContractUpgrade(tx: SignedTransaction) =
|
||||
authoriseContractUpgrade(tx, DummyContractV2::class)
|
||||
//endregion
|
||||
|
||||
//region Matchers
|
||||
private fun StartedNode<*>.hasDummyContractUpgradeTransaction() =
|
||||
hasContractUpgradeTransaction<DummyContract.State, DummyContractV2.State>()
|
||||
|
||||
private inline fun <reified FROM : Any, reified TO: Any> StartedNode<*>.hasContractUpgradeTransaction() =
|
||||
has<StateAndRef<ContractState>, ContractUpgradeLedgerTransaction>(
|
||||
"a contract upgrade transaction",
|
||||
{ getContractUpgradeTransaction(it) },
|
||||
isUpgrade<FROM, TO>())
|
||||
|
||||
private fun StartedNode<*>.getContractUpgradeTransaction(state: StateAndRef<ContractState>) = database.transaction {
|
||||
services.validatedTransactions.getTransaction(state.ref.txhash)!!
|
||||
.resolveContractUpgradeTransaction(services)
|
||||
}
|
||||
|
||||
private inline fun <reified FROM : Any, reified TO : Any> isUpgrade() =
|
||||
isUpgradeFrom<FROM>() and isUpgradeTo<TO>()
|
||||
|
||||
private inline fun <reified T: Any> isUpgradeFrom() =
|
||||
has<ContractUpgradeLedgerTransaction, Any>("input data", { it.inputs.single().state.data }, isA<T>(anything))
|
||||
|
||||
private inline fun <reified T: Any> isUpgradeTo() =
|
||||
has<ContractUpgradeLedgerTransaction, Any>("output data", { it.outputs.single().data }, isA<T>(anything))
|
||||
//endregion
|
||||
}
|
@ -3,9 +3,9 @@ package net.corda.core.flows
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.natpryce.hamkrest.*
|
||||
import com.natpryce.hamkrest.assertion.assert
|
||||
import net.corda.core.CordaRuntimeException
|
||||
import net.corda.core.contracts.*
|
||||
import net.corda.core.flows.matchers.*
|
||||
import net.corda.core.flows.matchers.flow.willThrow
|
||||
import net.corda.core.flows.matchers.flow.willReturn
|
||||
import net.corda.core.flows.mixins.WithContracts
|
||||
import net.corda.core.flows.mixins.WithFinality
|
||||
import net.corda.core.identity.AbstractParty
|
||||
@ -48,7 +48,6 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
||||
}
|
||||
|
||||
override val mockNet = classMockNet
|
||||
override val magicNumber = 0
|
||||
|
||||
private val aliceNode = makeNode(ALICE_NAME)
|
||||
private val bobNode = makeNode(BOB_NAME)
|
||||
@ -60,7 +59,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
||||
@Test
|
||||
fun `2 parties contract upgrade`() {
|
||||
// Create dummy contract.
|
||||
val signedByA = aliceNode.signDummyContract(alice.ref(1), bob.ref(1))
|
||||
val signedByA = aliceNode.signDummyContract(alice.ref(1),0, bob.ref(1))
|
||||
val stx = bobNode.addSignatureTo(signedByA)
|
||||
|
||||
aliceNode.finalise(stx, bob)
|
||||
@ -71,63 +70,24 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
||||
// The request is expected to be rejected because party B hasn't authorised the upgrade yet.
|
||||
assert.that(
|
||||
aliceNode.initiateDummyContractUpgrade(atx),
|
||||
fails<UnexpectedFlowEndException>())
|
||||
willThrow<UnexpectedFlowEndException>())
|
||||
|
||||
// Party B authorise the contract state upgrade, and immediately deauthorise the same.
|
||||
assert.that(bobNode.authoriseDummyContractUpgrade(btx), succeeds())
|
||||
assert.that(bobNode.deauthoriseContractUpgrade(btx), succeeds())
|
||||
assert.that(bobNode.authoriseDummyContractUpgrade(btx), willReturn())
|
||||
assert.that(bobNode.deauthoriseContractUpgrade(btx), willReturn())
|
||||
|
||||
// The request is expected to be rejected because party B has subsequently deauthorised a previously authorised upgrade.
|
||||
assert.that(
|
||||
aliceNode.initiateDummyContractUpgrade(atx),
|
||||
fails<UnexpectedFlowEndException>())
|
||||
willThrow<UnexpectedFlowEndException>())
|
||||
|
||||
// Party B authorise the contract state upgrade
|
||||
assert.that(bobNode.authoriseDummyContractUpgrade(btx), succeeds())
|
||||
assert.that(bobNode.authoriseDummyContractUpgrade(btx), willReturn())
|
||||
|
||||
// Party A initiates contract upgrade flow, expected to succeed this time.
|
||||
assert.that(
|
||||
aliceNode.initiateDummyContractUpgrade(atx),
|
||||
succeedsWith(
|
||||
aliceNode.hasDummyContractUpgradeTransaction()
|
||||
and bobNode.hasDummyContractUpgradeTransaction()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `2 parties contract upgrade using RPC`() = rpcDriver {
|
||||
val testUser = createTestUser()
|
||||
val rpcA = startProxy(aliceNode, testUser)
|
||||
val rpcB = startProxy(bobNode, testUser)
|
||||
|
||||
// Create, sign and finalise dummy contract.
|
||||
val signedByA = aliceNode.signDummyContract(alice.ref(1), bob.ref(1))
|
||||
val stx = bobNode.addSignatureTo(signedByA)
|
||||
assert.that(rpcA.finalise(stx, bob), rpcSucceeds())
|
||||
|
||||
val atx = aliceNode.getValidatedTransaction(stx)
|
||||
val btx = bobNode.getValidatedTransaction(stx)
|
||||
|
||||
// Cannot upgrade contract without prior authorisation from counterparty
|
||||
assert.that(
|
||||
rpcA.initiateDummyContractUpgrade(atx),
|
||||
rpcFails<CordaRuntimeException>())
|
||||
|
||||
// Party B authorises the contract state upgrade, and immediately deauthorises the same.
|
||||
assert.that(rpcB.authoriseDummyContractUpgrade(btx), rpcSucceeds())
|
||||
assert.that(rpcB.deauthoriseContractUpgrade(btx), rpcSucceeds())
|
||||
|
||||
// Cannot upgrade contract if counterparty has deauthorised a previously-given authority
|
||||
assert.that(
|
||||
rpcA.initiateDummyContractUpgrade(atx),
|
||||
rpcFails<CordaRuntimeException>())
|
||||
|
||||
// Party B authorise the contract state upgrade.
|
||||
assert.that(rpcB.authoriseDummyContractUpgrade(btx), rpcSucceeds())
|
||||
|
||||
// Party A initiates contract upgrade flow, expected to succeed this time.
|
||||
assert.that(
|
||||
rpcA.initiateDummyContractUpgrade(atx),
|
||||
rpcSucceedsWith(
|
||||
willReturn(
|
||||
aliceNode.hasDummyContractUpgradeTransaction()
|
||||
and bobNode.hasDummyContractUpgradeTransaction()))
|
||||
}
|
||||
@ -164,7 +124,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
||||
assert.that(aliceNode.getBaseStateFromVault(), hasContractState(isA<Cash.State>(anything)))
|
||||
|
||||
// Starts contract upgrade flow.
|
||||
assert.that(aliceNode.initiateContractUpgrade(stateAndRef, CashV2::class), succeeds())
|
||||
assert.that(aliceNode.initiateContractUpgrade(stateAndRef, CashV2::class), willReturn())
|
||||
|
||||
// Get contract state from the vault.
|
||||
val upgradedState = aliceNode.getCashStateFromVault()
|
||||
@ -182,7 +142,7 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
||||
addCommand(CashV2.Move(), alice.owningKey)
|
||||
}
|
||||
|
||||
assert.that(aliceNode.finalise(spendUpgradedTx), succeeds())
|
||||
assert.that(aliceNode.finalise(spendUpgradedTx), willReturn())
|
||||
assert.that(aliceNode.getCashStateFromVault(), hasContractState(equalTo(movedState)))
|
||||
}
|
||||
|
||||
@ -208,45 +168,12 @@ class ContractUpgradeFlowTest : WithContracts, WithFinality {
|
||||
override fun verify(tx: LedgerTransaction) {}
|
||||
}
|
||||
|
||||
@StartableByRPC
|
||||
class FinalityInvoker(private val transaction: SignedTransaction,
|
||||
private val extraRecipients: Set<Party>) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction = subFlow(FinalityFlow(transaction, extraRecipients))
|
||||
}
|
||||
|
||||
//region RPC DSL
|
||||
private fun RPCDriverDSL.startProxy(node: StartedNode<MockNode>, user: User): CordaRPCOps {
|
||||
return startRpcClient<CordaRPCOps>(
|
||||
rpcAddress = startRpcServer(
|
||||
rpcUser = user,
|
||||
ops = node.rpcOps
|
||||
).get().broker.hostAndPort!!,
|
||||
username = user.username,
|
||||
password = user.password
|
||||
).get()
|
||||
}
|
||||
|
||||
private fun RPCDriverDSL.createTestUser() = rpcTestUser.copy(permissions = setOf(
|
||||
startFlow<FinalityInvoker>(),
|
||||
startFlow<ContractUpgradeFlow.Initiate<*, *>>(),
|
||||
startFlow<ContractUpgradeFlow.Authorise>(),
|
||||
startFlow<ContractUpgradeFlow.Deauthorise>()
|
||||
))
|
||||
//endregion
|
||||
|
||||
//region Operations
|
||||
private fun StartedNode<*>.initiateDummyContractUpgrade(tx: SignedTransaction) =
|
||||
initiateContractUpgrade(tx, DummyContractV2::class)
|
||||
|
||||
private fun StartedNode<*>.authoriseDummyContractUpgrade(tx: SignedTransaction) =
|
||||
authoriseContractUpgrade(tx, DummyContractV2::class)
|
||||
|
||||
private fun CordaRPCOps.initiateDummyContractUpgrade(tx: SignedTransaction) =
|
||||
initiateContractUpgrade(tx, DummyContractV2::class)
|
||||
|
||||
private fun CordaRPCOps.authoriseDummyContractUpgrade(tx: SignedTransaction) =
|
||||
authoriseContractUpgrade(tx, DummyContractV2::class)
|
||||
//endregion
|
||||
|
||||
//region Matchers
|
||||
|
@ -2,8 +2,8 @@ package net.corda.core.flows
|
||||
|
||||
import com.natpryce.hamkrest.and
|
||||
import com.natpryce.hamkrest.assertion.assert
|
||||
import net.corda.core.flows.matchers.fails
|
||||
import net.corda.core.flows.matchers.succeedsWith
|
||||
import net.corda.core.flows.matchers.flow.willThrow
|
||||
import net.corda.core.flows.matchers.flow.willReturn
|
||||
import net.corda.core.flows.mixins.WithFinality
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
@ -42,9 +42,9 @@ class FinalityFlowTests : WithFinality {
|
||||
|
||||
assert.that(
|
||||
aliceNode.finalise(stx),
|
||||
succeedsWith(
|
||||
requiredSignatures(1)
|
||||
and transactionVisibleTo(bobNode)))
|
||||
willReturn(
|
||||
requiredSignatures(1)
|
||||
and transactionVisibleTo(bobNode)))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -54,7 +54,7 @@ class FinalityFlowTests : WithFinality {
|
||||
|
||||
assert.that(
|
||||
aliceNode.finalise(stx),
|
||||
fails<IllegalArgumentException>())
|
||||
willThrow<IllegalArgumentException>())
|
||||
}
|
||||
|
||||
private fun StartedNode<*>.signCashTransactionWith(other: Party): SignedTransaction {
|
||||
|
@ -4,7 +4,7 @@ import co.paralleluniverse.fibers.Suspendable
|
||||
import com.natpryce.hamkrest.assertion.assert
|
||||
import com.natpryce.hamkrest.equalTo
|
||||
import com.natpryce.hamkrest.isA
|
||||
import net.corda.core.flows.matchers.succeedsWith
|
||||
import net.corda.core.flows.matchers.flow.willReturn
|
||||
import net.corda.core.flows.mixins.WithMockNet
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.utilities.UntrustworthyData
|
||||
@ -60,7 +60,7 @@ class ReceiveMultipleFlowTests : WithMockNet {
|
||||
|
||||
assert.that(
|
||||
nodes[0].startFlowAndRunNetwork(initiatingFlow),
|
||||
succeedsWith(isA(equalTo(answer))))
|
||||
willReturn(isA(equalTo(answer))))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -72,7 +72,7 @@ class ReceiveMultipleFlowTests : WithMockNet {
|
||||
|
||||
assert.that(
|
||||
nodes[0].startFlowAndRunNetwork(ParallelAlgorithmMap(nodes[1].info.singleIdentity(), nodes[2].info.singleIdentity())),
|
||||
succeedsWith(equalTo(doubleValue * stringValue.length)))
|
||||
willReturn(equalTo(doubleValue * stringValue.length)))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -84,7 +84,7 @@ class ReceiveMultipleFlowTests : WithMockNet {
|
||||
|
||||
assert.that(
|
||||
nodes[0].startFlowAndRunNetwork(ParallelAlgorithmList(nodes[1].info.singleIdentity(), nodes[2].info.singleIdentity())),
|
||||
succeedsWith(equalTo(listOf(value1, value2))))
|
||||
willReturn(equalTo(listOf(value1, value2))))
|
||||
}
|
||||
|
||||
class ParallelAlgorithmMap(doubleMember: Party, stringMember: Party) : AlgorithmDefinition(doubleMember, stringMember) {
|
||||
|
@ -1,69 +0,0 @@
|
||||
package net.corda.core.flows.matchers
|
||||
|
||||
import com.natpryce.hamkrest.MatchResult
|
||||
import com.natpryce.hamkrest.Matcher
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
|
||||
/**
|
||||
* Matches a Flow that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> succeeds() = object : Matcher<FlowStateMachine<T>> {
|
||||
override val description: String = "is a flow that succeeds"
|
||||
|
||||
override fun invoke(actual: FlowStateMachine<T>): MatchResult = try {
|
||||
actual.resultFuture.getOrThrow()
|
||||
MatchResult.Match
|
||||
} catch (e: Exception) {
|
||||
MatchResult.Mismatch("Failed with $e")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a Flow that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> succeedsWith(successMatcher: Matcher<T>) = object : Matcher<FlowStateMachine<out T>> {
|
||||
override val description: String = "is a flow that succeeds with a value that ${successMatcher.description}"
|
||||
|
||||
override fun invoke(actual: FlowStateMachine<out T>): MatchResult = try {
|
||||
successMatcher(actual.resultFuture.getOrThrow())
|
||||
} catch (e: Exception) {
|
||||
MatchResult.Mismatch("Failed with $e")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a Flow that fails, with an exception matched by the given matcher.
|
||||
*/
|
||||
inline fun <reified E: Exception> fails(failureMatcher: Matcher<E>) = object : Matcher<FlowStateMachine<*>> {
|
||||
override val description: String
|
||||
get() = "is a flow that fails with a ${E::class.java.simpleName} that ${failureMatcher.description}"
|
||||
|
||||
override fun invoke(actual: FlowStateMachine<*>): MatchResult = try {
|
||||
actual.resultFuture.getOrThrow()
|
||||
MatchResult.Mismatch("Succeeded")
|
||||
} catch (e: Exception) {
|
||||
when(e) {
|
||||
is E -> failureMatcher(e)
|
||||
else -> MatchResult.Mismatch("Failure class was ${e.javaClass}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a Flow that fails, with an exception of the specified type.
|
||||
*/
|
||||
inline fun <reified E: Exception> fails() = object : Matcher<FlowStateMachine<*>> {
|
||||
override val description: String
|
||||
get() = "is a flow that fails with a ${E::class.java}"
|
||||
|
||||
override fun invoke(actual: FlowStateMachine<*>): MatchResult = try {
|
||||
actual.resultFuture.getOrThrow()
|
||||
MatchResult.Mismatch("Succeeded")
|
||||
} catch (e: Exception) {
|
||||
when(e) {
|
||||
is E -> MatchResult.Match
|
||||
else -> MatchResult.Mismatch("Failure class was ${e.javaClass}")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package net.corda.core.flows.matchers
|
||||
|
||||
import com.natpryce.hamkrest.MatchResult
|
||||
import com.natpryce.hamkrest.Matcher
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
import java.util.concurrent.Future
|
||||
|
||||
/**
|
||||
* Matches a Flow that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> willReturn() = object : Matcher<Future<T>> {
|
||||
override val description: String = "is a future that will succeed"
|
||||
|
||||
override fun invoke(actual: Future<T>): MatchResult = try {
|
||||
actual.getOrThrow()
|
||||
MatchResult.Match
|
||||
} catch (e: Exception) {
|
||||
MatchResult.Mismatch("Failed with $e")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a Flow that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> willSucceedWithResult(successMatcher: Matcher<T>) = object : Matcher<Future<out T>> {
|
||||
override val description: String = "is a future that will succeed with a value that ${successMatcher.description}"
|
||||
|
||||
override fun invoke(actual: Future<out T>): MatchResult = try {
|
||||
successMatcher(actual.getOrThrow())
|
||||
} catch (e: Exception) {
|
||||
MatchResult.Mismatch("Failed with $e")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a Flow that fails, with an exception matched by the given matcher.
|
||||
*/
|
||||
inline fun <reified E: Exception> willFailWithException(failureMatcher: Matcher<E>) = object : Matcher<Future<*>> {
|
||||
override val description: String
|
||||
get() = "is a future that will fail with a ${E::class.java.simpleName} that ${failureMatcher.description}"
|
||||
|
||||
override fun invoke(actual: Future<*>): MatchResult = try {
|
||||
actual.getOrThrow()
|
||||
MatchResult.Mismatch("Succeeded")
|
||||
} catch (e: Exception) {
|
||||
when(e) {
|
||||
is E -> failureMatcher(e)
|
||||
else -> MatchResult.Mismatch("Failure class was ${e.javaClass}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a Flow that fails, with an exception of the specified type.
|
||||
*/
|
||||
inline fun <reified E: Exception> willThrow() = object : Matcher<Future<*>> {
|
||||
override val description: String
|
||||
get() = "is a future that will fail with a ${E::class.java}"
|
||||
|
||||
override fun invoke(actual: Future<*>): MatchResult = try {
|
||||
actual.getOrThrow()
|
||||
MatchResult.Mismatch("Succeeded")
|
||||
} catch (e: Exception) {
|
||||
when(e) {
|
||||
is E -> MatchResult.Match
|
||||
else -> MatchResult.Mismatch("Failure class was ${e.javaClass}")
|
||||
}
|
||||
}
|
||||
}
|
@ -1,69 +0,0 @@
|
||||
package net.corda.core.flows.matchers
|
||||
|
||||
import com.natpryce.hamkrest.MatchResult
|
||||
import com.natpryce.hamkrest.Matcher
|
||||
import net.corda.core.messaging.FlowHandle
|
||||
import net.corda.core.utilities.getOrThrow
|
||||
|
||||
/**
|
||||
* Matches an RPC flow handle that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> rpcSucceeds() = object : Matcher<FlowHandle<T>> {
|
||||
override val description: String = "is an RPC flow handle that succeeds"
|
||||
|
||||
override fun invoke(actual: FlowHandle<T>): MatchResult = try {
|
||||
actual.returnValue.getOrThrow()
|
||||
MatchResult.Match
|
||||
} catch (e: Exception) {
|
||||
MatchResult.Mismatch("Failed with $e")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches an RPC flow handle that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> rpcSucceedsWith(successMatcher: Matcher<T>) = object : Matcher<FlowHandle<T>> {
|
||||
override val description: String = "is an RPC flow handle that succeeds with a value that ${successMatcher.description}"
|
||||
|
||||
override fun invoke(actual: FlowHandle<T>): MatchResult = try {
|
||||
successMatcher(actual.returnValue.getOrThrow())
|
||||
} catch (e: Exception) {
|
||||
MatchResult.Mismatch("Failed with $e")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches an RPC Flow handle that fails, with an exception matched by the given matcher.
|
||||
*/
|
||||
inline fun <reified E: Exception> rpcFails(failureMatcher: Matcher<E>) = object : Matcher<FlowHandle<*>> {
|
||||
override val description: String
|
||||
get() = "is an RPC flow handle that fails with a ${E::class.java.simpleName} that ${failureMatcher.description}"
|
||||
|
||||
override fun invoke(actual: FlowHandle<*>): MatchResult = try {
|
||||
actual.returnValue.getOrThrow()
|
||||
MatchResult.Mismatch("Succeeded")
|
||||
} catch (e: Exception) {
|
||||
when(e) {
|
||||
is E -> failureMatcher(e)
|
||||
else -> MatchResult.Mismatch("Failure class was ${e.javaClass}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a Flow that fails, with an exception of the specified type.
|
||||
*/
|
||||
inline fun <reified E: Exception> rpcFails() = object : Matcher<FlowHandle<*>> {
|
||||
override val description: String
|
||||
get() = "is an RPC flow handle that fails with a ${E::class.java}"
|
||||
|
||||
override fun invoke(actual: FlowHandle<*>): MatchResult = try {
|
||||
actual.returnValue.getOrThrow()
|
||||
MatchResult.Mismatch("Succeeded")
|
||||
} catch (e: Exception) {
|
||||
when(e) {
|
||||
is E -> MatchResult.Match
|
||||
else -> MatchResult.Mismatch("Failure class was ${e.javaClass}")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.corda.core.flows.matchers.flow
|
||||
|
||||
import com.natpryce.hamkrest.Matcher
|
||||
import com.natpryce.hamkrest.has
|
||||
import net.corda.core.flows.matchers.willThrow
|
||||
import net.corda.core.flows.matchers.willFailWithException
|
||||
import net.corda.core.flows.matchers.willReturn
|
||||
import net.corda.core.flows.matchers.willSucceedWithResult
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
|
||||
/**
|
||||
* Matches a Flow that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> willReturn() = has(FlowStateMachine<T>::resultFuture, willReturn())
|
||||
|
||||
/**
|
||||
* Matches a Flow that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> willReturn(successMatcher: Matcher<T>) = has(
|
||||
FlowStateMachine<out T>::resultFuture,
|
||||
willSucceedWithResult(successMatcher))
|
||||
|
||||
/**
|
||||
* Matches a Flow that fails, with an exception matched by the given matcher.
|
||||
*/
|
||||
inline fun <reified E: Exception> willThrow(failureMatcher: Matcher<E>) = has(
|
||||
FlowStateMachine<*>::resultFuture,
|
||||
willFailWithException(failureMatcher))
|
||||
|
||||
/**
|
||||
* Matches a Flow that fails, with an exception of the specified type.
|
||||
*/
|
||||
inline fun <reified E: Exception> willThrow() = has(
|
||||
FlowStateMachine<*>::resultFuture,
|
||||
willThrow<E>())
|
@ -0,0 +1,33 @@
|
||||
package net.corda.core.flows.matchers.rpc
|
||||
|
||||
import com.natpryce.hamkrest.Matcher
|
||||
import com.natpryce.hamkrest.has
|
||||
import net.corda.core.flows.matchers.willThrow
|
||||
import net.corda.core.flows.matchers.willFailWithException
|
||||
import net.corda.core.flows.matchers.willReturn
|
||||
import net.corda.core.flows.matchers.willSucceedWithResult
|
||||
import net.corda.core.messaging.FlowHandle
|
||||
|
||||
/**
|
||||
* Matches a flow handle that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> willReturn() = has(FlowHandle<T>::returnValue, willReturn())
|
||||
|
||||
/**
|
||||
* Matches a flow handle that succeeds with a result matched by the given matcher
|
||||
*/
|
||||
fun <T> willReturn(successMatcher: Matcher<T>) = has(FlowHandle<out T>::returnValue, willSucceedWithResult(successMatcher))
|
||||
|
||||
/**
|
||||
* Matches a flow handle that fails, with an exception matched by the given matcher.
|
||||
*/
|
||||
inline fun <reified E: Exception> willThrow(failureMatcher: Matcher<E>) = has(
|
||||
FlowHandle<*>::returnValue,
|
||||
willFailWithException(failureMatcher))
|
||||
|
||||
/**
|
||||
* Matches a flow handle that fails, with an exception of the specified type.
|
||||
*/
|
||||
inline fun <reified E: Exception> willThrow() = has(
|
||||
FlowHandle<*>::returnValue,
|
||||
willThrow<E>())
|
@ -21,10 +21,8 @@ import kotlin.reflect.KClass
|
||||
*/
|
||||
interface WithContracts : WithMockNet {
|
||||
|
||||
val magicNumber: Int
|
||||
|
||||
//region Generators
|
||||
fun createDummyContract(owner: PartyAndReference, vararg others: PartyAndReference) =
|
||||
fun createDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
|
||||
DummyContract.generateInitial(
|
||||
magicNumber,
|
||||
mockNet.defaultNotaryIdentity,
|
||||
@ -33,21 +31,11 @@ interface WithContracts : WithMockNet {
|
||||
//region
|
||||
|
||||
//region Operations
|
||||
fun StartedNode<*>.createConfidentialIdentity(party: Party) = database.transaction {
|
||||
services.keyManagementService.freshKeyAndCert(
|
||||
services.myInfo.legalIdentitiesAndCerts.single { it.name == party.name },
|
||||
false)
|
||||
}
|
||||
fun StartedNode<*>.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
|
||||
services.signDummyContract(owner, magicNumber, *others).andRunNetwork()
|
||||
|
||||
fun StartedNode<*>.verifyAndRegister(identity: PartyAndCertificate) = database.transaction {
|
||||
services.identityService.verifyAndRegisterIdentity(identity)
|
||||
}
|
||||
|
||||
fun StartedNode<*>.signDummyContract(owner: PartyAndReference, vararg others: PartyAndReference) =
|
||||
services.signDummyContract(owner, *others).andRunNetwork()
|
||||
|
||||
fun ServiceHub.signDummyContract(owner: PartyAndReference, vararg others: PartyAndReference) =
|
||||
signInitialTransaction(createDummyContract(owner, *others))
|
||||
fun ServiceHub.signDummyContract(owner: PartyAndReference, magicNumber: Int = 0, vararg others: PartyAndReference) =
|
||||
signInitialTransaction(createDummyContract(owner, magicNumber, *others))
|
||||
|
||||
fun StartedNode<*>.collectSignatures(ptx: SignedTransaction) =
|
||||
startFlowAndRunNetwork(CollectSignaturesFlow(ptx, emptySet()))
|
||||
|
@ -1,9 +1,12 @@
|
||||
package net.corda.core.flows.mixins
|
||||
|
||||
import co.paralleluniverse.fibers.Suspendable
|
||||
import com.natpryce.hamkrest.Matcher
|
||||
import com.natpryce.hamkrest.equalTo
|
||||
import net.corda.core.flows.ContractUpgradeFlowTest
|
||||
import net.corda.core.flows.FinalityFlow
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.flows.StartableByRPC
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.messaging.CordaRPCOps
|
||||
import net.corda.core.messaging.startFlow
|
||||
@ -22,7 +25,7 @@ interface WithFinality : WithMockNet {
|
||||
}
|
||||
|
||||
fun CordaRPCOps.finalise(stx: SignedTransaction, vararg parties: Party) =
|
||||
startFlow(ContractUpgradeFlowTest::FinalityInvoker, stx, parties.toSet())
|
||||
startFlow(::FinalityInvoker, stx, parties.toSet())
|
||||
.andRunNetwork()
|
||||
//endregion
|
||||
|
||||
@ -33,4 +36,11 @@ interface WithFinality : WithMockNet {
|
||||
equalTo(actual)(other.getValidatedTransaction(actual))
|
||||
}
|
||||
//endregion
|
||||
|
||||
@StartableByRPC
|
||||
class FinalityInvoker(private val transaction: SignedTransaction,
|
||||
private val extraRecipients: Set<Party>) : FlowLogic<SignedTransaction>() {
|
||||
@Suspendable
|
||||
override fun call(): SignedTransaction = subFlow(FinalityFlow(transaction, extraRecipients))
|
||||
}
|
||||
}
|
@ -4,6 +4,8 @@ import com.natpryce.hamkrest.*
|
||||
import net.corda.core.contracts.ContractState
|
||||
import net.corda.core.flows.FlowLogic
|
||||
import net.corda.core.identity.CordaX500Name
|
||||
import net.corda.core.identity.Party
|
||||
import net.corda.core.identity.PartyAndCertificate
|
||||
import net.corda.core.internal.FlowStateMachine
|
||||
import net.corda.core.transactions.SignedTransaction
|
||||
import net.corda.core.transactions.TransactionBuilder
|
||||
@ -33,10 +35,7 @@ interface WithMockNet {
|
||||
/**
|
||||
* Run the mock network before proceeding
|
||||
*/
|
||||
fun <T: Any> T.andRunNetwork(): T {
|
||||
mockNet.runNetwork()
|
||||
return this
|
||||
}
|
||||
fun <T: Any> T.andRunNetwork(): T = apply { mockNet.runNetwork() }
|
||||
|
||||
//region Operations
|
||||
/**
|
||||
@ -62,6 +61,16 @@ interface WithMockNet {
|
||||
*/
|
||||
fun <T> StartedNode<*>.startFlowAndRunNetwork(logic: FlowLogic<T>): FlowStateMachine<T> =
|
||||
startFlow(logic).andRunNetwork()
|
||||
|
||||
fun StartedNode<*>.createConfidentialIdentity(party: Party) = database.transaction {
|
||||
services.keyManagementService.freshKeyAndCert(
|
||||
services.myInfo.legalIdentitiesAndCerts.single { it.name == party.name },
|
||||
false)
|
||||
}
|
||||
|
||||
fun StartedNode<*>.verifyAndRegister(identity: PartyAndCertificate) = database.transaction {
|
||||
services.identityService.verifyAndRegisterIdentity(identity)
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Matchers
|
||||
|
Loading…
Reference in New Issue
Block a user