mirror of
https://github.com/corda/corda.git
synced 2024-12-23 23:02:29 +00:00
Add Cash*Flow tests
Add tests for CashIssueFlow, CashPaymentFlow and CashExitFlow. While these were mostly covered by other tests already, CashExistFlow was not, and any bugs would be harder to identify because they are mixed in with other functionality (i.e. vault tests)
This commit is contained in:
parent
848988bf1c
commit
48b121d145
finance/src
main/kotlin/net/corda/contracts
test/kotlin/net/corda/flows
node/src/main/kotlin/net/corda/node/services/vault
@ -154,6 +154,7 @@ class Cash : OnLedgerAsset<Currency, Cash.Commands, Cash.State>() {
|
||||
fun generateIssue(tx: TransactionBuilder, amount: Amount<Issued<Currency>>, owner: CompositeKey, notary: Party) {
|
||||
check(tx.inputStates().isEmpty())
|
||||
check(tx.outputStates().map { it.data }.sumCashOrNull() == null)
|
||||
require(amount.quantity > 0)
|
||||
val at = amount.token.issuer
|
||||
tx.addOutputState(TransactionState(State(amount, owner), notary))
|
||||
tx.addCommand(generateIssueCommand(), at.party.owningKey)
|
||||
|
@ -29,6 +29,7 @@ abstract class AbstractConserveAmount<S : FungibleAsset<T>, C : CommandData, T :
|
||||
@Throws(InsufficientBalanceException::class)
|
||||
private fun gatherCoins(acceptableCoins: Collection<StateAndRef<S>>,
|
||||
amount: Amount<T>): Pair<ArrayList<StateAndRef<S>>, Amount<T>> {
|
||||
require(amount.quantity > 0) { "Cannot gather zero coins" }
|
||||
val gathered = arrayListOf<StateAndRef<S>>()
|
||||
var gatheredAmount = Amount(0, amount.token)
|
||||
for (c in acceptableCoins) {
|
||||
|
72
finance/src/test/kotlin/net/corda/flows/CashExitFlowTests.kt
Normal file
72
finance/src/test/kotlin/net/corda/flows/CashExitFlowTests.kt
Normal file
@ -0,0 +1,72 @@
|
||||
package net.corda.flows
|
||||
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.contracts.`issued by`
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNetwork.MockNode
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class CashExitFlowTests {
|
||||
private val net = MockNetwork(servicePeerAllocationStrategy = RoundRobin())
|
||||
private val initialBalance = 2000.DOLLARS
|
||||
private val ref = OpaqueBytes.of(0x01)
|
||||
private lateinit var bankOfCordaNode: MockNode
|
||||
private lateinit var bankOfCorda: Party
|
||||
private lateinit var notaryNode: MockNode
|
||||
private lateinit var notary: Party
|
||||
|
||||
@Before
|
||||
fun start() {
|
||||
val nodes = net.createTwoNodes()
|
||||
notaryNode = nodes.first
|
||||
bankOfCordaNode = nodes.second
|
||||
notary = notaryNode.info.notaryIdentity
|
||||
bankOfCorda = bankOfCordaNode.info.legalIdentity
|
||||
|
||||
net.runNetwork()
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance, ref,
|
||||
bankOfCorda,
|
||||
notary)).resultFuture
|
||||
net.runNetwork()
|
||||
future.getOrThrow()
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
net.stopNodes()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exit some cash`() {
|
||||
val exitAmount = 500.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashExitFlow(exitAmount,
|
||||
ref)).resultFuture
|
||||
net.runNetwork()
|
||||
val exitTx = future.getOrThrow().tx
|
||||
val expected = (initialBalance - exitAmount).`issued by`(bankOfCorda.ref(ref))
|
||||
assertEquals(1, exitTx.inputs.size)
|
||||
assertEquals(1, exitTx.outputs.size)
|
||||
val output = exitTx.outputs.map { it.data }.filterIsInstance<Cash.State>().single()
|
||||
assertEquals(expected, output.amount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `exit zero cash`() {
|
||||
val expected = 0.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashExitFlow(expected,
|
||||
ref)).resultFuture
|
||||
net.runNetwork()
|
||||
assertFailsWith<CashException> {
|
||||
future.getOrThrow()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package net.corda.flows
|
||||
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.contracts.`issued by`
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNetwork.MockNode
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class CashIssueFlowTests {
|
||||
private val net = MockNetwork(servicePeerAllocationStrategy = RoundRobin())
|
||||
private lateinit var bankOfCordaNode: MockNode
|
||||
private lateinit var bankOfCorda: Party
|
||||
private lateinit var notaryNode: MockNode
|
||||
private lateinit var notary: Party
|
||||
|
||||
@Before
|
||||
fun start() {
|
||||
val nodes = net.createTwoNodes()
|
||||
notaryNode = nodes.first
|
||||
bankOfCordaNode = nodes.second
|
||||
notary = notaryNode.info.notaryIdentity
|
||||
bankOfCorda = bankOfCordaNode.info.legalIdentity
|
||||
|
||||
net.runNetwork()
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
net.stopNodes()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `issue some cash`() {
|
||||
val expected = 500.DOLLARS
|
||||
val ref = OpaqueBytes.of(0x01)
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(expected, ref,
|
||||
bankOfCorda,
|
||||
notary)).resultFuture
|
||||
net.runNetwork()
|
||||
val issueTx = future.getOrThrow()
|
||||
val output = issueTx.tx.outputs.single().data as Cash.State
|
||||
assertEquals(expected.`issued by`(bankOfCorda.ref(ref)), output.amount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `issue zero cash`() {
|
||||
val expected = 0.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(expected, OpaqueBytes.of(0x01),
|
||||
bankOfCorda,
|
||||
notary)).resultFuture
|
||||
net.runNetwork()
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
future.getOrThrow()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package net.corda.flows
|
||||
|
||||
import net.corda.contracts.asset.Cash
|
||||
import net.corda.core.contracts.DOLLARS
|
||||
import net.corda.core.contracts.`issued by`
|
||||
import net.corda.core.crypto.Party
|
||||
import net.corda.core.getOrThrow
|
||||
import net.corda.core.serialization.OpaqueBytes
|
||||
import net.corda.testing.node.InMemoryMessagingNetwork.ServicePeerAllocationStrategy.RoundRobin
|
||||
import net.corda.testing.node.MockNetwork
|
||||
import net.corda.testing.node.MockNetwork.MockNode
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.util.concurrent.ExecutionException
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
class CashPaymentFlowTests {
|
||||
private val net = MockNetwork(servicePeerAllocationStrategy = RoundRobin())
|
||||
private val initialBalance = 2000.DOLLARS
|
||||
private val ref = OpaqueBytes.of(0x01)
|
||||
private lateinit var bankOfCordaNode: MockNode
|
||||
private lateinit var bankOfCorda: Party
|
||||
private lateinit var notaryNode: MockNode
|
||||
private lateinit var notary: Party
|
||||
|
||||
@Before
|
||||
fun start() {
|
||||
val nodes = net.createTwoNodes()
|
||||
notaryNode = nodes.first
|
||||
bankOfCordaNode = nodes.second
|
||||
notary = notaryNode.info.notaryIdentity
|
||||
bankOfCorda = bankOfCordaNode.info.legalIdentity
|
||||
|
||||
net.runNetwork()
|
||||
val future = bankOfCordaNode.services.startFlow(CashIssueFlow(initialBalance, ref,
|
||||
bankOfCorda,
|
||||
notary)).resultFuture
|
||||
net.runNetwork()
|
||||
future.getOrThrow()
|
||||
}
|
||||
|
||||
@After
|
||||
fun cleanUp() {
|
||||
net.stopNodes()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pay some cash`() {
|
||||
val payTo = notaryNode.info.legalIdentity
|
||||
val expected = 500.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashPaymentFlow(expected,
|
||||
payTo)).resultFuture
|
||||
net.runNetwork()
|
||||
val paymentTx = future.getOrThrow()
|
||||
val states = paymentTx.tx.outputs.map { it.data }.filterIsInstance<Cash.State>()
|
||||
val ourState = states.single { it.owner != payTo.owningKey }
|
||||
val paymentState = states.single { it.owner == payTo.owningKey }
|
||||
assertEquals(expected.`issued by`(bankOfCorda.ref(ref)), paymentState.amount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pay more than we have`() {
|
||||
val payTo = notaryNode.info.legalIdentity
|
||||
val expected = 4000.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashPaymentFlow(expected,
|
||||
payTo)).resultFuture
|
||||
net.runNetwork()
|
||||
assertFailsWith<CashException> {
|
||||
future.getOrThrow()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `pay zero cash`() {
|
||||
val payTo = notaryNode.info.legalIdentity
|
||||
val expected = 0.DOLLARS
|
||||
val future = bankOfCordaNode.services.startFlow(CashPaymentFlow(expected,
|
||||
payTo)).resultFuture
|
||||
net.runNetwork()
|
||||
assertFailsWith<IllegalArgumentException> {
|
||||
future.getOrThrow()
|
||||
}
|
||||
}
|
||||
}
|
@ -528,9 +528,11 @@ class NodeVaultService(private val services: ServiceHub, dataSourceProperties: P
|
||||
* @param amount the amount to gather states up to.
|
||||
* @throws InsufficientBalanceException if there isn't enough value in the states to cover the requested amount.
|
||||
*/
|
||||
// TODO: Merge this with the function in [AbstractConserveAmount]
|
||||
@Throws(InsufficientBalanceException::class)
|
||||
private fun gatherCoins(acceptableCoins: Collection<StateAndRef<Cash.State>>,
|
||||
amount: Amount<Currency>): Pair<ArrayList<StateAndRef<Cash.State>>, Amount<Currency>> {
|
||||
require(amount.quantity > 0) { "Cannot gather zero coins" }
|
||||
val gathered = arrayListOf<StateAndRef<Cash.State>>()
|
||||
var gatheredAmount = Amount(0, amount.token)
|
||||
for (c in acceptableCoins) {
|
||||
|
Loading…
Reference in New Issue
Block a user