Updated and fixed all failing Unit tests from perftestcordapp module (temporarily set to @Ignore).

This commit is contained in:
josecoll 2017-11-19 19:48:29 +00:00
parent 738067f673
commit 730aed6cf2
3 changed files with 112 additions and 88 deletions

View File

@ -1,8 +1,5 @@
package com.r3.corda.enterprise.perftestcordapp.contracts package net.corda.finance.contracts
import com.r3.corda.enterprise.perftestcordapp.DOLLARS
import com.r3.corda.enterprise.perftestcordapp.`issued by`
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.*
import net.corda.core.contracts.* import net.corda.core.contracts.*
import net.corda.core.identity.AnonymousParty import net.corda.core.identity.AnonymousParty
import net.corda.core.identity.Party import net.corda.core.identity.Party
@ -12,9 +9,15 @@ import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.TransactionBuilder import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.days import net.corda.core.utilities.days
import net.corda.core.utilities.seconds import net.corda.core.utilities.seconds
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.finance.contracts.asset.*
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash
import net.corda.testing.node.MockServices import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import org.junit.Ignore import org.junit.Ignore
import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.Parameterized import org.junit.runners.Parameterized
@ -25,17 +28,30 @@ import kotlin.test.assertTrue
// TODO: The generate functions aren't tested by these tests: add them. // TODO: The generate functions aren't tested by these tests: add them.
interface CommercialPaperTestTemplate { interface ICommercialPaperTestTemplate {
fun getPaper(): CommercialPaper.State fun getPaper(): ICommercialPaperState
fun getIssueCommand(notary: Party): CommandData fun getIssueCommand(notary: Party): CommandData
fun getRedeemCommand(notary: Party): CommandData fun getRedeemCommand(notary: Party): CommandData
fun getMoveCommand(): CommandData fun getMoveCommand(): CommandData
fun getContract(): ContractClassName fun getContract(): ContractClassName
} }
class JavaCommercialPaperTest : ICommercialPaperTestTemplate {
override fun getPaper(): ICommercialPaperState = JavaCommercialPaper.State(
MEGA_CORP.ref(123),
MEGA_CORP,
1000.DOLLARS `issued by` MEGA_CORP.ref(123),
TEST_TX_TIME + 7.days
)
class KotlinCommercialPaperTest : CommercialPaperTestTemplate { override fun getIssueCommand(notary: Party): CommandData = JavaCommercialPaper.Commands.Issue()
override fun getPaper(): CommercialPaper.State = CommercialPaper.State( override fun getRedeemCommand(notary: Party): CommandData = JavaCommercialPaper.Commands.Redeem()
override fun getMoveCommand(): CommandData = JavaCommercialPaper.Commands.Move()
override fun getContract() = JavaCommercialPaper.JCP_PROGRAM_ID
}
class KotlinCommercialPaperTest : ICommercialPaperTestTemplate {
override fun getPaper(): ICommercialPaperState = CommercialPaper.State(
issuance = MEGA_CORP.ref(123), issuance = MEGA_CORP.ref(123),
owner = MEGA_CORP, owner = MEGA_CORP,
faceValue = 1000.DOLLARS `issued by` MEGA_CORP.ref(123), faceValue = 1000.DOLLARS `issued by` MEGA_CORP.ref(123),
@ -48,8 +64,8 @@ class KotlinCommercialPaperTest : CommercialPaperTestTemplate {
override fun getContract() = CommercialPaper.CP_PROGRAM_ID override fun getContract() = CommercialPaper.CP_PROGRAM_ID
} }
class KotlinCommercialPaperLegacyTest : CommercialPaperTestTemplate { class KotlinCommercialPaperLegacyTest : ICommercialPaperTestTemplate {
override fun getPaper(): CommercialPaper.State = CommercialPaper.State( override fun getPaper(): ICommercialPaperState = CommercialPaper.State(
issuance = MEGA_CORP.ref(123), issuance = MEGA_CORP.ref(123),
owner = MEGA_CORP, owner = MEGA_CORP,
faceValue = 1000.DOLLARS `issued by` MEGA_CORP.ref(123), faceValue = 1000.DOLLARS `issued by` MEGA_CORP.ref(123),
@ -62,17 +78,19 @@ class KotlinCommercialPaperLegacyTest : CommercialPaperTestTemplate {
override fun getContract() = CommercialPaper.CP_PROGRAM_ID override fun getContract() = CommercialPaper.CP_PROGRAM_ID
} }
@Ignore
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class CommercialPaperTestsGeneric { class CommercialPaperTestsGeneric {
companion object { companion object {
@Parameterized.Parameters @JvmStatic @Parameterized.Parameters
fun data() = listOf(KotlinCommercialPaperTest(), KotlinCommercialPaperLegacyTest()) @JvmStatic
fun data() = listOf(JavaCommercialPaperTest(), KotlinCommercialPaperTest(), KotlinCommercialPaperLegacyTest())
} }
@Parameterized.Parameter @Parameterized.Parameter
lateinit var thisTest: CommercialPaperTestTemplate lateinit var thisTest: ICommercialPaperTestTemplate
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
val issuer = MEGA_CORP.ref(123) val issuer = MEGA_CORP.ref(123)
@Test @Test
@ -87,7 +105,7 @@ class CommercialPaperTestsGeneric {
// Some CP is issued onto the ledger by MegaCorp. // Some CP is issued onto the ledger by MegaCorp.
transaction("Issuance") { transaction("Issuance") {
attachments(CP_PROGRAM_ID, CommercialPaper.CP_PROGRAM_ID) attachments(CP_PROGRAM_ID, JavaCommercialPaper.JCP_PROGRAM_ID)
output(thisTest.getContract(), "paper") { thisTest.getPaper() } output(thisTest.getContract(), "paper") { thisTest.getPaper() }
command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) }
timeWindow(TEST_TX_TIME) timeWindow(TEST_TX_TIME)
@ -97,11 +115,11 @@ class CommercialPaperTestsGeneric {
// The CP is sold to alice for her $900, $100 less than the face value. At 10% interest after only 7 days, // The CP is sold to alice for her $900, $100 less than the face value. At 10% interest after only 7 days,
// that sounds a bit too good to be true! // that sounds a bit too good to be true!
transaction("Trade") { transaction("Trade") {
attachments(Cash.PROGRAM_ID, CommercialPaper.CP_PROGRAM_ID) attachments(Cash.PROGRAM_ID, JavaCommercialPaper.JCP_PROGRAM_ID)
input("paper") input("paper")
input("alice's $900") input("alice's $900")
output(Cash.PROGRAM_ID, "borrowed $900") { 900.DOLLARS.CASH issuedBy issuer ownedBy MEGA_CORP } output(Cash.PROGRAM_ID, "borrowed $900") { 900.DOLLARS.CASH issuedBy issuer ownedBy MEGA_CORP }
output(thisTest.getContract(), "alice's paper") { "paper".output<CommercialPaper.State>().withOwner(ALICE) } output(thisTest.getContract(), "alice's paper") { "paper".output<ICommercialPaperState>().withOwner(ALICE) }
command(ALICE_PUBKEY) { Cash.Commands.Move() } command(ALICE_PUBKEY) { Cash.Commands.Move() }
command(MEGA_CORP_PUBKEY) { thisTest.getMoveCommand() } command(MEGA_CORP_PUBKEY) { thisTest.getMoveCommand() }
this.verifies() this.verifies()
@ -110,7 +128,7 @@ class CommercialPaperTestsGeneric {
// Time passes, and Alice redeem's her CP for $1000, netting a $100 profit. MegaCorp has received $1200 // Time passes, and Alice redeem's her CP for $1000, netting a $100 profit. MegaCorp has received $1200
// as a single payment from somewhere and uses it to pay Alice off, keeping the remaining $200 as change. // as a single payment from somewhere and uses it to pay Alice off, keeping the remaining $200 as change.
transaction("Redemption") { transaction("Redemption") {
attachments(CP_PROGRAM_ID, CommercialPaper.CP_PROGRAM_ID) attachments(CP_PROGRAM_ID, JavaCommercialPaper.JCP_PROGRAM_ID)
input("alice's paper") input("alice's paper")
input("some profits") input("some profits")
@ -137,7 +155,7 @@ class CommercialPaperTestsGeneric {
timeWindow(TEST_TX_TIME + 8.days) timeWindow(TEST_TX_TIME + 8.days)
tweak { tweak {
output(thisTest.getContract()) { "paper".output<CommercialPaper.State>() } output(thisTest.getContract()) { "paper".output<ICommercialPaperState>() }
this `fails with` "must be destroyed" this `fails with` "must be destroyed"
} }
@ -150,7 +168,7 @@ class CommercialPaperTestsGeneric {
fun `key mismatch at issue`() { fun `key mismatch at issue`() {
transaction { transaction {
attachment(CP_PROGRAM_ID) attachment(CP_PROGRAM_ID)
attachment(CP_PROGRAM_ID) attachment(JavaCommercialPaper.JCP_PROGRAM_ID)
output(thisTest.getContract()) { thisTest.getPaper() } output(thisTest.getContract()) { thisTest.getPaper() }
command(MINI_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } command(MINI_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) }
timeWindow(TEST_TX_TIME) timeWindow(TEST_TX_TIME)
@ -162,7 +180,7 @@ class CommercialPaperTestsGeneric {
fun `face value is not zero`() { fun `face value is not zero`() {
transaction { transaction {
attachment(CP_PROGRAM_ID) attachment(CP_PROGRAM_ID)
attachment(CP_PROGRAM_ID) attachment(JavaCommercialPaper.JCP_PROGRAM_ID)
output(thisTest.getContract()) { thisTest.getPaper().withFaceValue(0.DOLLARS `issued by` issuer) } output(thisTest.getContract()) { thisTest.getPaper().withFaceValue(0.DOLLARS `issued by` issuer) }
command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) }
timeWindow(TEST_TX_TIME) timeWindow(TEST_TX_TIME)
@ -174,7 +192,7 @@ class CommercialPaperTestsGeneric {
fun `maturity date not in the past`() { fun `maturity date not in the past`() {
transaction { transaction {
attachment(CP_PROGRAM_ID) attachment(CP_PROGRAM_ID)
attachment(CP_PROGRAM_ID) attachment(JavaCommercialPaper.JCP_PROGRAM_ID)
output(thisTest.getContract()) { thisTest.getPaper().withMaturityDate(TEST_TX_TIME - 10.days) } output(thisTest.getContract()) { thisTest.getPaper().withMaturityDate(TEST_TX_TIME - 10.days) }
command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) }
timeWindow(TEST_TX_TIME) timeWindow(TEST_TX_TIME)
@ -186,7 +204,7 @@ class CommercialPaperTestsGeneric {
fun `issue cannot replace an existing state`() { fun `issue cannot replace an existing state`() {
transaction { transaction {
attachment(CP_PROGRAM_ID) attachment(CP_PROGRAM_ID)
attachment(CP_PROGRAM_ID) attachment(JavaCommercialPaper.JCP_PROGRAM_ID)
input(thisTest.getContract(), thisTest.getPaper()) input(thisTest.getContract(), thisTest.getPaper())
output(thisTest.getContract()) { thisTest.getPaper() } output(thisTest.getContract()) { thisTest.getPaper() }
command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) } command(MEGA_CORP_PUBKEY) { thisTest.getIssueCommand(DUMMY_NOTARY) }
@ -215,8 +233,8 @@ class CommercialPaperTestsGeneric {
// @Test // @Test
@Ignore @Ignore
fun `issue move and then redeem`() = withTestSerialization{ fun `issue move and then redeem`() = withTestSerialization {
val aliceDatabaseAndServices = MockServices.makeTestDatabaseAndMockServices(keys = listOf(ALICE_KEY)) val aliceDatabaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(ALICE_KEY))
val databaseAlice = aliceDatabaseAndServices.first val databaseAlice = aliceDatabaseAndServices.first
aliceServices = aliceDatabaseAndServices.second aliceServices = aliceDatabaseAndServices.second
aliceVaultService = aliceServices.vaultService aliceVaultService = aliceServices.vaultService
@ -226,7 +244,7 @@ class CommercialPaperTestsGeneric {
aliceVaultService = aliceServices.vaultService aliceVaultService = aliceServices.vaultService
} }
val bigCorpDatabaseAndServices = MockServices.makeTestDatabaseAndMockServices(keys = listOf(BIG_CORP_KEY)) val bigCorpDatabaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(BIG_CORP_KEY))
val databaseBigCorp = bigCorpDatabaseAndServices.first val databaseBigCorp = bigCorpDatabaseAndServices.first
bigCorpServices = bigCorpDatabaseAndServices.second bigCorpServices = bigCorpDatabaseAndServices.second
bigCorpVaultService = bigCorpServices.vaultService bigCorpVaultService = bigCorpServices.vaultService

View File

@ -30,7 +30,6 @@ import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Ignore
import org.junit.Test import org.junit.Test
import java.security.KeyPair import java.security.KeyPair
import java.util.* import java.util.*
@ -80,7 +79,6 @@ fun ServiceHub.fillWithSomeTestCash(howMuch: Amount<Currency>,
return Vault(states) return Vault(states)
} }
@Ignore
class CashTests { class CashTests {
private val defaultRef = OpaqueBytes(ByteArray(1, { 1 })) private val defaultRef = OpaqueBytes(ByteArray(1, { 1 }))
private val defaultIssuer = MEGA_CORP.ref(defaultRef) private val defaultIssuer = MEGA_CORP.ref(defaultRef)
@ -132,7 +130,7 @@ class CashTests {
} }
@Test @Test
fun trivial() { fun trivial() = withTestSerialization {
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
input(Cash.PROGRAM_ID) { inState } input(Cash.PROGRAM_ID) { inState }
@ -166,10 +164,11 @@ class CashTests {
this.verifies() this.verifies()
} }
} }
Unit
} }
@Test @Test
fun `issue by move`() { fun `issue by move`() = withTestSerialization {
// Check we can't "move" money into existence. // Check we can't "move" money into existence.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -179,10 +178,11 @@ class CashTests {
this `fails with` "there is at least one cash input for this group" this `fails with` "there is at least one cash input for this group"
} }
Unit
} }
@Test @Test
fun issue() { fun issue() = withTestSerialization {
// Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised // Check we can issue money only as long as the issuer institution is a command signer, i.e. any recognised
// institution is allowed to issue as much cash as they want. // institution is allowed to issue as much cash as they want.
transaction { transaction {
@ -202,6 +202,7 @@ class CashTests {
command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() } command(MINI_CORP_PUBKEY) { Cash.Commands.Issue() }
this.verifies() this.verifies()
} }
Unit
} }
@Test @Test
@ -231,7 +232,7 @@ class CashTests {
} }
@Test @Test
fun `extended issue examples`() { fun `extended issue examples`() = withTestSerialization {
// We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer. // We can consume $1000 in a transaction and output $2000 as long as it's signed by an issuer.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -281,6 +282,7 @@ class CashTests {
} }
this.verifies() this.verifies()
} }
Unit
} }
/** /**
@ -303,7 +305,7 @@ class CashTests {
} }
@Test @Test
fun testMergeSplit() { fun testMergeSplit() = withTestSerialization {
// Splitting value works. // Splitting value works.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -330,10 +332,11 @@ class CashTests {
this.verifies() this.verifies()
} }
} }
Unit
} }
@Test @Test
fun zeroSizedValues() { fun zeroSizedValues() = withTestSerialization {
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
input(Cash.PROGRAM_ID) { inState } input(Cash.PROGRAM_ID) { inState }
@ -349,10 +352,11 @@ class CashTests {
command(ALICE_PUBKEY) { Cash.Commands.Move() } command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "zero sized outputs" this `fails with` "zero sized outputs"
} }
Unit
} }
@Test @Test
fun trivialMismatches() { fun trivialMismatches() = withTestSerialization {
// Can't change issuer. // Can't change issuer.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -410,10 +414,11 @@ class CashTests {
command(ALICE_PUBKEY) { Cash.Commands.Move() } command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "for reference [01]" this `fails with` "for reference [01]"
} }
Unit
} }
@Test @Test
fun exitLedger() { fun exitLedger() = withTestSerialization {
// Single input/output straightforward case. // Single input/output straightforward case.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -436,10 +441,11 @@ class CashTests {
} }
} }
} }
Unit
} }
@Test @Test
fun `exit ledger with multiple issuers`() { fun `exit ledger with multiple issuers`() = withTestSerialization {
// Multi-issuer case. // Multi-issuer case.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -459,10 +465,11 @@ class CashTests {
command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) } command(MINI_CORP_PUBKEY) { Cash.Commands.Exit(200.DOLLARS `issued by` MINI_CORP.ref(defaultRef)) }
this.verifies() this.verifies()
} }
Unit
} }
@Test @Test
fun `exit cash not held by its issuer`() { fun `exit cash not held by its issuer`() = withTestSerialization {
// Single input/output straightforward case. // Single input/output straightforward case.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -472,10 +479,11 @@ class CashTests {
command(ALICE_PUBKEY) { Cash.Commands.Move() } command(ALICE_PUBKEY) { Cash.Commands.Move() }
this `fails with` "the amounts balance" this `fails with` "the amounts balance"
} }
Unit
} }
@Test @Test
fun multiIssuer() { fun multiIssuer() = withTestSerialization {
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
// Gather 2000 dollars from two different issuers. // Gather 2000 dollars from two different issuers.
@ -500,10 +508,11 @@ class CashTests {
output(Cash.PROGRAM_ID) { inState.copy(owner = AnonymousParty(BOB_PUBKEY)) issuedBy MINI_CORP } output(Cash.PROGRAM_ID) { inState.copy(owner = AnonymousParty(BOB_PUBKEY)) issuedBy MINI_CORP }
this.verifies() this.verifies()
} }
Unit
} }
@Test @Test
fun multiCurrency() { fun multiCurrency() = withTestSerialization {
// Check we can do an atomic currency trade tx. // Check we can do an atomic currency trade tx.
transaction { transaction {
attachment(Cash.PROGRAM_ID) attachment(Cash.PROGRAM_ID)
@ -516,6 +525,7 @@ class CashTests {
this.verifies() this.verifies()
} }
Unit
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -828,7 +838,7 @@ class CashTests {
// Double spend. // Double spend.
@Test @Test
fun chainCashDoubleSpendFailsWith() { fun chainCashDoubleSpendFailsWith() = withTestSerialization {
val mockService = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset"), MEGA_CORP.name, MEGA_CORP_KEY) val mockService = MockServices(listOf("com.r3.corda.enterprise.perftestcordapp.contracts.asset"), MEGA_CORP.name, MEGA_CORP_KEY)
ledger(mockService) { ledger(mockService) {
@ -864,6 +874,7 @@ class CashTests {
this.verifies() this.verifies()
} }
Unit
} }
@Test @Test

View File

@ -1,17 +1,6 @@
package com.r3.corda.enterprise.perftestcordapp.flows package net.corda.node.messaging
// NB: Unlike the other flow tests in this package, this is not originally copied from net.corda.finance, but
// from net.corda.node.messaging
import co.paralleluniverse.fibers.Suspendable import co.paralleluniverse.fibers.Suspendable
import com.r3.corda.enterprise.perftestcordapp.DOLLARS
import com.r3.corda.enterprise.perftestcordapp.`issued by`
import com.r3.corda.enterprise.perftestcordapp.contracts.CommercialPaper
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.CASH
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.Cash
import com.r3.corda.enterprise.perftestcordapp.contracts.asset.fillWithSomeTestCash
import com.r3.corda.enterprise.perftestcordapp.flows.TwoPartyTradeFlow.Buyer
import com.r3.corda.enterprise.perftestcordapp.flows.TwoPartyTradeFlow.Seller
import net.corda.core.concurrent.CordaFuture import net.corda.core.concurrent.CordaFuture
import net.corda.core.contracts.* import net.corda.core.contracts.*
import net.corda.core.crypto.* import net.corda.core.crypto.*
@ -36,6 +25,13 @@ import net.corda.core.utilities.days
import net.corda.core.utilities.getOrThrow import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.toNonEmptySet import net.corda.core.utilities.toNonEmptySet
import net.corda.core.utilities.unwrap import net.corda.core.utilities.unwrap
import net.corda.finance.DOLLARS
import net.corda.finance.`issued by`
import net.corda.finance.contracts.CommercialPaper
import net.corda.finance.contracts.asset.CASH
import net.corda.finance.contracts.asset.Cash
import net.corda.finance.flows.TwoPartyTradeFlow.Buyer
import net.corda.finance.flows.TwoPartyTradeFlow.Seller
import net.corda.node.internal.StartedNode import net.corda.node.internal.StartedNode
import net.corda.node.services.api.Checkpoint import net.corda.node.services.api.Checkpoint
import net.corda.node.services.api.CheckpointStorage import net.corda.node.services.api.CheckpointStorage
@ -43,11 +39,11 @@ import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.persistence.DBTransactionStorage import net.corda.node.services.persistence.DBTransactionStorage
import net.corda.node.utilities.CordaPersistence import net.corda.node.utilities.CordaPersistence
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.contracts.fillWithSomeTestCash
import net.corda.testing.node.* import net.corda.testing.node.*
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Ignore
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.Parameterized import org.junit.runners.Parameterized
@ -74,23 +70,19 @@ internal fun CheckpointStorage.checkpoints(): List<Checkpoint> {
return checkpoints return checkpoints
} }
/** /**
* In this example, Alice wishes to sell her commercial paper to Bob in return for $1,000,000 and they wish to do * In this example, Alice wishes to sell her commercial paper to Bob in return for $1,000,000 and they wish to do
* it on the ledger atomically. Therefore they must work together to build a transaction. * it on the ledger atomically. Therefore they must work together to build a transaction.
* *
* We assume that Alice and Bob already found each other via some market, and have agreed the details already. * We assume that Alice and Bob already found each other via some market, and have agreed the details already.
*/ */
@Ignore
@RunWith(Parameterized::class) @RunWith(Parameterized::class)
class TwoPartyTradeFlowTests(private val anonymous: Boolean) { class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
companion object { companion object {
private val cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts") private val cordappPackages = listOf("com.r3.corda.enterprise.perftestcordapp.contracts")
@JvmStatic @JvmStatic
@Parameterized.Parameters(name = "Anonymous = {0}") @Parameterized.Parameters(name = "Anonymous = {0}")
fun data(): Collection<Boolean> { fun data(): Collection<Boolean> = listOf(true, false)
return listOf(true, false)
}
} }
private lateinit var mockNet: MockNetwork private lateinit var mockNet: MockNetwork
@ -119,6 +111,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
val bankNode = mockNet.createPartyNode(BOC_NAME) val bankNode = mockNet.createPartyNode(BOC_NAME)
val alice = aliceNode.info.singleIdentity() val alice = aliceNode.info.singleIdentity()
val bank = bankNode.info.singleIdentity() val bank = bankNode.info.singleIdentity()
val bob = bobNode.info.singleIdentity()
val notary = mockNet.defaultNotaryIdentity val notary = mockNet.defaultNotaryIdentity
val cashIssuer = bank.ref(1) val cashIssuer = bank.ref(1)
val cpIssuer = bank.ref(1, 2, 3) val cpIssuer = bank.ref(1, 2, 3)
@ -136,9 +129,9 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
1200.DOLLARS `issued by` bank.ref(0), null, notary).second 1200.DOLLARS `issued by` bank.ref(0), null, notary).second
} }
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, bankNode) insertFakeTransactions(alicesFakePaper, aliceNode, alice, notaryNode, bankNode)
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notary, aliceNode, bobNode, val (bobStateMachine, aliceResult) = runBuyerAndSeller(notary, bob, aliceNode, bobNode,
"alice's paper".outputStateAndRef()) "alice's paper".outputStateAndRef())
// TODO: Verify that the result was inserted into the transaction database. // TODO: Verify that the result was inserted into the transaction database.
@ -169,6 +162,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
val bankNode = mockNet.createPartyNode(BOC_NAME) val bankNode = mockNet.createPartyNode(BOC_NAME)
val alice = aliceNode.info.singleIdentity() val alice = aliceNode.info.singleIdentity()
val bank = bankNode.info.singleIdentity() val bank = bankNode.info.singleIdentity()
val bob = bobNode.info.singleIdentity()
val issuer = bank.ref(1) val issuer = bank.ref(1)
val notary = mockNet.defaultNotaryIdentity val notary = mockNet.defaultNotaryIdentity
@ -185,7 +179,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
1200.DOLLARS `issued by` bank.ref(0), null, notary).second 1200.DOLLARS `issued by` bank.ref(0), null, notary).second
} }
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, bankNode) insertFakeTransactions(alicesFakePaper, aliceNode, alice, notaryNode, bankNode)
val cashLockId = UUID.randomUUID() val cashLockId = UUID.randomUUID()
bobNode.database.transaction { bobNode.database.transaction {
@ -196,7 +190,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
} }
} }
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notary, aliceNode, bobNode, val (bobStateMachine, aliceResult) = runBuyerAndSeller(notary, bob, aliceNode, bobNode,
"alice's paper".outputStateAndRef()) "alice's paper".outputStateAndRef())
assertEquals(aliceResult.getOrThrow(), bobStateMachine.getOrThrow().resultFuture.getOrThrow()) assertEquals(aliceResult.getOrThrow(), bobStateMachine.getOrThrow().resultFuture.getOrThrow())
@ -232,6 +226,7 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
val notary = mockNet.defaultNotaryIdentity val notary = mockNet.defaultNotaryIdentity
val alice = aliceNode.info.singleIdentity() val alice = aliceNode.info.singleIdentity()
val bank = bankNode.info.singleIdentity() val bank = bankNode.info.singleIdentity()
val bob = bobNode.info.singleIdentity()
val issuer = bank.ref(1, 2, 3) val issuer = bank.ref(1, 2, 3)
bobNode.database.transaction { bobNode.database.transaction {
@ -242,8 +237,8 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
fillUpForSeller(false, issuer, alice, fillUpForSeller(false, issuer, alice,
1200.DOLLARS `issued by` bank.ref(0), null, notary).second 1200.DOLLARS `issued by` bank.ref(0), null, notary).second
} }
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, bankNode) insertFakeTransactions(alicesFakePaper, aliceNode, alice, notaryNode, bankNode)
val aliceFuture = runBuyerAndSeller(notary, aliceNode, bobNode, "alice's paper".outputStateAndRef()).sellerResult val aliceFuture = runBuyerAndSeller(notary, bob, aliceNode, bobNode, "alice's paper".outputStateAndRef()).sellerResult
// Everything is on this thread so we can now step through the flow one step at a time. // Everything is on this thread so we can now step through the flow one step at a time.
// Seller Alice already sent a message to Buyer Bob. Pump once: // Seller Alice already sent a message to Buyer Bob. Pump once:
@ -355,16 +350,16 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
val bobsFakeCash = bobNode.database.transaction { val bobsFakeCash = bobNode.database.transaction {
fillUpForBuyer(false, issuer, AnonymousParty(bob.owningKey), notary) fillUpForBuyer(false, issuer, AnonymousParty(bob.owningKey), notary)
}.second }.second
val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, bankNode) val bobsSignedTxns = insertFakeTransactions(bobsFakeCash, bobNode, bob, notaryNode, bankNode)
val alicesFakePaper = aliceNode.database.transaction { val alicesFakePaper = aliceNode.database.transaction {
fillUpForSeller(false, issuer, alice, fillUpForSeller(false, issuer, alice,
1200.DOLLARS `issued by` bank.ref(0), attachmentID, notary).second 1200.DOLLARS `issued by` bank.ref(0), attachmentID, notary).second
} }
val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, bankNode) val alicesSignedTxns = insertFakeTransactions(alicesFakePaper, aliceNode, alice, notaryNode, bankNode)
mockNet.runNetwork() // Clear network map registration messages mockNet.runNetwork() // Clear network map registration messages
runBuyerAndSeller(notary, aliceNode, bobNode, "alice's paper".outputStateAndRef()) runBuyerAndSeller(notary, bob, aliceNode, bobNode, "alice's paper".outputStateAndRef())
mockNet.runNetwork() mockNet.runNetwork()
@ -439,10 +434,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
val bobNode = makeNodeWithTracking(BOB_NAME) val bobNode = makeNodeWithTracking(BOB_NAME)
val bankNode = makeNodeWithTracking(BOC_NAME) val bankNode = makeNodeWithTracking(BOC_NAME)
mockNet.runNetwork()
val notary = mockNet.defaultNotaryIdentity val notary = mockNet.defaultNotaryIdentity
val alice: Party = aliceNode.info.singleIdentity() val alice: Party = aliceNode.info.singleIdentity()
val bank: Party = bankNode.info.singleIdentity() val bank: Party = bankNode.info.singleIdentity()
val bob = bobNode.info.singleIdentity()
val issuer = bank.ref(1, 2, 3) val issuer = bank.ref(1, 2, 3)
ledger(aliceNode.services) { ledger(aliceNode.services) {
@ -461,22 +456,20 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
val bobsFakeCash = bobNode.database.transaction { val bobsFakeCash = bobNode.database.transaction {
fillUpForBuyer(false, issuer, AnonymousParty(bobsKey), notary) fillUpForBuyer(false, issuer, AnonymousParty(bobsKey), notary)
}.second }.second
insertFakeTransactions(bobsFakeCash, bobNode, notaryNode, bankNode) insertFakeTransactions(bobsFakeCash, bobNode, bob, notaryNode, bankNode)
val alicesFakePaper = aliceNode.database.transaction { val alicesFakePaper = aliceNode.database.transaction {
fillUpForSeller(false, issuer, alice, fillUpForSeller(false, issuer, alice,
1200.DOLLARS `issued by` bank.ref(0), attachmentID, notary).second 1200.DOLLARS `issued by` bank.ref(0), attachmentID, notary).second
} }
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, bankNode) insertFakeTransactions(alicesFakePaper, aliceNode, alice, notaryNode, bankNode)
mockNet.runNetwork() // Clear network map registration messages
val aliceTxStream = aliceNode.services.validatedTransactions.track().updates val aliceTxStream = aliceNode.services.validatedTransactions.track().updates
val aliceTxMappings = with(aliceNode) { val aliceTxMappings = with(aliceNode) {
database.transaction { services.stateMachineRecordedTransactionMapping.track().updates } database.transaction { services.stateMachineRecordedTransactionMapping.track().updates }
} }
val aliceSmId = runBuyerAndSeller(notary, aliceNode, bobNode, val aliceSmId = runBuyerAndSeller(notary, bob, aliceNode, bobNode,
"alice's paper".outputStateAndRef()).sellerId "alice's paper".outputStateAndRef()).sellerId
mockNet.runNetwork() mockNet.runNetwork()
@ -536,12 +529,13 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
) )
private fun runBuyerAndSeller(notary: Party, private fun runBuyerAndSeller(notary: Party,
buyer: Party,
sellerNode: StartedNode<MockNetwork.MockNode>, sellerNode: StartedNode<MockNetwork.MockNode>,
buyerNode: StartedNode<MockNetwork.MockNode>, buyerNode: StartedNode<MockNetwork.MockNode>,
assetToSell: StateAndRef<OwnableState>): RunResult { assetToSell: StateAndRef<OwnableState>): RunResult {
val buyerFlows: Observable<out FlowLogic<*>> = buyerNode.internals.registerInitiatedFlow(BuyerAcceptor::class.java) val buyerFlows: Observable<out FlowLogic<*>> = buyerNode.internals.registerInitiatedFlow(BuyerAcceptor::class.java)
val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine } val firstBuyerFiber = buyerFlows.toFuture().map { it.stateMachine }
val seller = SellerInitiator(buyerNode.info.chooseIdentity(), notary, assetToSell, 1000.DOLLARS, anonymous) val seller = SellerInitiator(buyer, notary, assetToSell, 1000.DOLLARS, anonymous)
val sellerResult = sellerNode.services.startFlow(seller).resultFuture val sellerResult = sellerNode.services.startFlow(seller).resultFuture
return RunResult(firstBuyerFiber, sellerResult, seller.stateMachine.id) return RunResult(firstBuyerFiber, sellerResult, seller.stateMachine.id)
} }
@ -594,7 +588,6 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
val bobNode = mockNet.createPartyNode(BOB_NAME) val bobNode = mockNet.createPartyNode(BOB_NAME)
val bankNode = mockNet.createPartyNode(BOC_NAME) val bankNode = mockNet.createPartyNode(BOC_NAME)
mockNet.runNetwork()
val notary = mockNet.defaultNotaryIdentity val notary = mockNet.defaultNotaryIdentity
val alice = aliceNode.info.singleIdentity() val alice = aliceNode.info.singleIdentity()
val bob = bobNode.info.singleIdentity() val bob = bobNode.info.singleIdentity()
@ -608,12 +601,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
fillUpForSeller(aliceError, issuer, alice,1200.DOLLARS `issued by` issuer, null, notary).second fillUpForSeller(aliceError, issuer, alice,1200.DOLLARS `issued by` issuer, null, notary).second
} }
insertFakeTransactions(bobsBadCash, bobNode, notaryNode, bankNode) insertFakeTransactions(bobsBadCash, bobNode, bob, notaryNode, bankNode)
insertFakeTransactions(alicesFakePaper, aliceNode, notaryNode, bankNode) insertFakeTransactions(alicesFakePaper, aliceNode, alice, notaryNode, bankNode)
mockNet.runNetwork() // Clear network map registration messages val (bobStateMachine, aliceResult) = runBuyerAndSeller(notary, bob, aliceNode, bobNode, "alice's paper".outputStateAndRef())
val (bobStateMachine, aliceResult) = runBuyerAndSeller(notary, aliceNode, bobNode, "alice's paper".outputStateAndRef())
mockNet.runNetwork() mockNet.runNetwork()
@ -633,14 +624,14 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
private fun insertFakeTransactions( private fun insertFakeTransactions(
wtxToSign: List<WireTransaction>, wtxToSign: List<WireTransaction>,
node: StartedNode<*>, node: StartedNode<*>,
identity: Party,
notaryNode: StartedNode<*>, notaryNode: StartedNode<*>,
vararg extraSigningNodes: StartedNode<*>): Map<SecureHash, SignedTransaction> { vararg extraSigningNodes: StartedNode<*>): Map<SecureHash, SignedTransaction> {
val notaryParty = mockNet.defaultNotaryIdentity
val notaryParty = notaryNode.info.legalIdentities[0]
val signed = wtxToSign.map { val signed = wtxToSign.map {
val id = it.id val id = it.id
val sigs = mutableListOf<TransactionSignature>() val sigs = mutableListOf<TransactionSignature>()
val nodeKey = node.info.chooseIdentity().owningKey val nodeKey = identity.owningKey
sigs += node.services.keyManagementService.sign( sigs += node.services.keyManagementService.sign(
SignableData(id, SignatureMetadata(1, Crypto.findSignatureScheme(nodeKey).schemeNumberID)), SignableData(id, SignatureMetadata(1, Crypto.findSignatureScheme(nodeKey).schemeNumberID)),
nodeKey nodeKey
@ -650,11 +641,12 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
notaryParty.owningKey notaryParty.owningKey
) )
extraSigningNodes.forEach { currentNode -> extraSigningNodes.forEach { currentNode ->
val currentIdentity = currentNode.info.singleIdentity()
sigs += currentNode.services.keyManagementService.sign( sigs += currentNode.services.keyManagementService.sign(
SignableData(id, SignatureMetadata( SignableData(id, SignatureMetadata(
1, 1,
Crypto.findSignatureScheme(currentNode.info.chooseIdentity().owningKey).schemeNumberID)), Crypto.findSignatureScheme(currentIdentity.owningKey).schemeNumberID)),
currentNode.info.chooseIdentity().owningKey) currentIdentity.owningKey)
} }
SignedTransaction(it, sigs) SignedTransaction(it, sigs)
} }
@ -742,7 +734,10 @@ class TwoPartyTradeFlowTests(private val anonymous: Boolean) {
} }
class RecordingTransactionStorage(val database: CordaPersistence, val delegate: WritableTransactionStorage) : WritableTransactionStorage, SingletonSerializeAsToken() { class RecordingTransactionStorage(
private val database: CordaPersistence,
private val delegate: WritableTransactionStorage
) : WritableTransactionStorage, SingletonSerializeAsToken() {
override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> { override fun track(): DataFeed<List<SignedTransaction>, SignedTransaction> {
return database.transaction { return database.transaction {
delegate.track() delegate.track()