Test DSL: update tests to handle new transaction constraints

This commit is contained in:
Andrius Dagys 2017-08-09 16:17:26 +01:00
parent f5776d6bd7
commit 73664c3383
13 changed files with 32 additions and 26 deletions

View File

@ -289,7 +289,7 @@ abstract class TypeOnlyCommandData : CommandData {
data class Command<T : CommandData>(val value: T, val signers: List<PublicKey>) {
// TODO Introduce NonEmptyList?
init {
require(signers.isNotEmpty())
require(signers.isNotEmpty()) { "The list of signers cannot be empty" }
}
constructor(data: T, key: PublicKey) : this(data, listOf(key))

View File

@ -169,8 +169,6 @@ class Cap {
output { stateInitial }
timeWindow(TEST_TX_TIME_1)
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -56,8 +56,6 @@ class Caplet {
output { stateStart }
timeWindow(TEST_TX_TIME_1)
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -53,8 +53,6 @@ class FXFwdTimeOption
output { inState }
timeWindow(TEST_TX_TIME_1)
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -45,8 +45,6 @@ class FXSwap {
output { inState }
timeWindow(TEST_TX_TIME_1)
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -136,8 +136,6 @@ class IRS {
output { stateInitial }
timeWindow(TEST_TX_TIME_1)
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -145,8 +145,6 @@ class RollOutTests {
output { stateStart }
timeWindow(TEST_TX_TIME_1)
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -62,8 +62,6 @@ class Swaption {
output { stateInitial }
timeWindow(TEST_TX_TIME_1)
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -48,12 +48,9 @@ class ZeroCouponBond {
@Test
fun `issue - signature`() {
transaction {
output { inState }
this `fails with` "transaction has a single command"
tweak {
command(acmeCorp.owningKey) { UniversalContract.Commands.Issue() }
this `fails with` "the transaction is signed by all liable parties"

View File

@ -4,6 +4,7 @@ import kotlin.Unit;
import net.corda.core.contracts.PartyAndReference;
import net.corda.core.identity.AnonymousParty;
import net.corda.core.utilities.OpaqueBytes;
import net.corda.testing.DummyCommandData;
import org.junit.Test;
import static net.corda.finance.CurrencyUtils.DOLLARS;
@ -24,16 +25,17 @@ public class CashTestsJava {
ledger(lg -> {
lg.transaction(tx -> {
tx.input(inState);
tx.failsWith("the amounts balance");
tx.tweak(tw -> {
tw.output(new Cash.State(issuedBy(DOLLARS(2000), defaultIssuer), new AnonymousParty(getMINI_CORP_PUBKEY())));
tw.command(getMEGA_CORP_PUBKEY(), new Cash.Commands.Move());
return tw.failsWith("the amounts balance");
});
tx.tweak(tw -> {
tw.output(outState);
// No command arguments
tw.command(getMEGA_CORP_PUBKEY(), DummyCommandData.INSTANCE);
// Invalid command
return tw.failsWith("required net.corda.finance.contracts.asset.Cash.Commands.Move command");
});
tx.tweak(tw -> {

View File

@ -85,15 +85,16 @@ class CashTests : TestDependencyInjectionBase() {
fun trivial() {
transaction {
input { inState }
this `fails with` "the amounts balance"
tweak {
output { outState.copy(amount = 2000.DOLLARS `issued by` defaultIssuer) }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "the amounts balance"
}
tweak {
output { outState }
// No command arguments
command(ALICE_PUBKEY) { DummyCommandData }
// Invalid command
this `fails with` "required net.corda.finance.contracts.asset.Cash.Commands.Move command"
}
tweak {
@ -279,12 +280,14 @@ class CashTests : TestDependencyInjectionBase() {
transaction {
input { inState }
input { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "zero sized inputs"
}
transaction {
input { inState }
output { inState }
output { inState.copy(amount = 0.DOLLARS `issued by` defaultIssuer) }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "zero sized outputs"
}
}
@ -295,6 +298,7 @@ class CashTests : TestDependencyInjectionBase() {
transaction {
input { inState }
output { outState `issued by` MINI_CORP }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "the amounts balance"
}
// Can't change deposit reference when splitting.
@ -302,6 +306,7 @@ class CashTests : TestDependencyInjectionBase() {
val splits2 = inState.amount.splitEvenly(2)
input { inState }
for (i in 0..1) output { outState.copy(amount = splits2[i]).editDepositRef(i.toByte()) }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "the amounts balance"
}
// Can't mix currencies.
@ -309,6 +314,7 @@ class CashTests : TestDependencyInjectionBase() {
input { inState }
output { outState.copy(amount = 800.DOLLARS `issued by` defaultIssuer) }
output { outState.copy(amount = 200.POUNDS `issued by` defaultIssuer) }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "the amounts balance"
}
transaction {
@ -320,6 +326,7 @@ class CashTests : TestDependencyInjectionBase() {
)
}
output { outState.copy(amount = 1150.DOLLARS `issued by` defaultIssuer) }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "the amounts balance"
}
// Can't have superfluous input states from different issuers.
@ -335,6 +342,7 @@ class CashTests : TestDependencyInjectionBase() {
input { inState }
input { inState.editDepositRef(3) }
output { outState.copy(amount = inState.amount * 2).editDepositRef(3) }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "for reference [01]"
}
}
@ -404,6 +412,7 @@ class CashTests : TestDependencyInjectionBase() {
// Gather 2000 dollars from two different issuers.
input { inState }
input { inState `issued by` MINI_CORP }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
// Can't merge them together.
tweak {
@ -420,7 +429,6 @@ class CashTests : TestDependencyInjectionBase() {
// This works.
output { inState.copy(owner = AnonymousParty(BOB_PUBKEY)) }
output { inState.copy(owner = AnonymousParty(BOB_PUBKEY)) `issued by` MINI_CORP }
command(ALICE_PUBKEY) { Cash.Commands.Move() }
this.verifies()
}
}

View File

@ -9,6 +9,7 @@ import net.corda.core.node.ServiceHub
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.transactions.WireTransaction
import net.corda.testing.contracts.DummyContract
import java.io.InputStream
import java.security.KeyPair
import java.security.PublicKey
@ -247,6 +248,7 @@ data class TestLedgerDSLInterpreter private constructor(
): WireTransaction {
val transactionLocation = getCallerLocation()
val transactionInterpreter = interpretTransactionDsl(transactionBuilder, dsl)
makeTxValid(transactionBuilder)
// Create the WireTransaction
val wireTransaction = transactionInterpreter.toWireTransaction()
// Record the output states
@ -262,6 +264,20 @@ data class TestLedgerDSLInterpreter private constructor(
return wireTransaction
}
/**
* This method fills the transaction builder with dummy components to satisfy the base transaction validity rules.
*
* A common pattern in our tests is using a base transaction and expressing the test cases using [tweak]s.
* The base transaction may not be valid, but it still gets recorded to the ledger. This causes a test failure,
* even though is not being used for anything afterwards.
*/
private fun makeTxValid(transactionBuilder: TransactionBuilder) {
if (transactionBuilder.commands().isEmpty()) transactionBuilder.addCommand(dummyCommand())
if (transactionBuilder.inputStates().isEmpty() && transactionBuilder.outputStates().isEmpty()) {
transactionBuilder.addOutputState(DummyContract.SingleOwnerState(owner = ALICE))
}
}
override fun _transaction(
transactionLabel: String?,
transactionBuilder: TransactionBuilder,

View File

@ -78,9 +78,6 @@ class TransactionDSL<out T : TransactionDSLInterpreter>(val interpreter: T) : Tr
fun input(state: ContractState) {
val transaction = ledgerInterpreter._unverifiedTransaction(null, TransactionBuilder(notary = DUMMY_NOTARY)) {
output { state }
// Add a dummy randomised output so that the transaction id differs when issuing the same state multiple times
val nonceState = DummyContract.SingleOwnerState(Random().nextInt(), DUMMY_NOTARY)
output { nonceState }
}
input(transaction.outRef<ContractState>(0).ref)
}