Improve robustness of the integration tests that commonly have false positives (Clinton)

This commit is contained in:
Shams Asari 2017-04-12 14:32:11 +01:00
parent 88b5e32ab2
commit 37dc6ead82
8 changed files with 66 additions and 14 deletions

View File

@ -37,6 +37,7 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
// Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')

View File

@ -3,7 +3,6 @@ package net.corda.irs
import com.google.common.net.HostAndPort
import com.google.common.util.concurrent.Futures
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.crypto.toBase58String
import net.corda.core.getOrThrow
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.DUMMY_BANK_A
@ -19,7 +18,9 @@ import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.IntegrationTestCategory
import net.corda.testing.http.HttpApi
import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import rx.observables.BlockingObservable
import java.net.URL
@ -46,9 +47,15 @@ class IRSDemoTest : IntegrationTestCategory {
).getOrThrow()
val nextFixingDates = getFixingDateObservable(nodeA.configuration)
val numADeals = getTradeCount(nodeAAddr)
val numBDeals = getTradeCount(nodeBAddr)
runUploadRates(controllerAddr)
runTrade(nodeAAddr)
assertThat(getTradeCount(nodeAAddr)).isEqualTo(numADeals + 1)
assertThat(getTradeCount(nodeBAddr)).isEqualTo(numBDeals + 1)
// Wait until the initial trade and all scheduled fixings up to the current date have finished
nextFixingDates.first { it == null || it > currentDate }
@ -88,4 +95,10 @@ class IRSDemoTest : IntegrationTestCategory {
val url = URL("http://$host/upload/interest-rates")
assert(uploadFile(url, fileContents))
}
private fun getTradeCount(nodeAddr: HostAndPort): Int {
val api = HttpApi.fromHostAndPort(nodeAddr, "api/irs")
val deals = api.getJson<Array<*>>("deals")
return deals.size
}
}

View File

@ -38,6 +38,7 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
// Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')

View File

@ -15,6 +15,7 @@ import net.corda.vega.api.PortfolioApi
import net.corda.vega.api.PortfolioApiUtils
import net.corda.vega.api.SwapDataModel
import net.corda.vega.api.SwapDataView
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import java.math.BigDecimal
import java.time.LocalDate
@ -22,13 +23,14 @@ import java.time.LocalDate
class SimmValuationTest : IntegrationTestCategory {
private companion object {
// SIMM demo can only currently handle one valuation date due to a lack of market data or a market data source.
val valuationDate = LocalDate.parse("2016-06-06")
val valuationDate: LocalDate = LocalDate.parse("2016-06-06")
val nodeALegalName = DUMMY_BANK_A.name
val nodeBLegalName = DUMMY_BANK_B.name
val testTradeId = "trade1"
}
@Test fun `runs SIMM valuation demo`() {
@Test
fun `runs SIMM valuation demo`() {
driver(isDebug = true) {
startNode(DUMMY_NOTARY.name, setOf(ServiceInfo(SimpleNotaryService.type))).getOrThrow()
val (nodeA, nodeB) = Futures.allAsList(startNode(nodeALegalName), startNode(nodeBLegalName)).getOrThrow()
@ -38,10 +40,12 @@ class SimmValuationTest : IntegrationTestCategory {
val nodeBParty = getPartyWithName(nodeAApi, nodeBLegalName)
val nodeAParty = getPartyWithName(nodeBApi, nodeALegalName)
assert(createTradeBetween(nodeAApi, nodeBParty, testTradeId))
assert(tradeExists(nodeBApi, nodeAParty, testTradeId))
assert(runValuationsBetween(nodeAApi, nodeBParty))
assert(valuationExists(nodeBApi, nodeAParty))
assertThat(createTradeBetween(nodeAApi, nodeBParty, testTradeId)).isTrue()
assertTradeExists(nodeBApi, nodeAParty, testTradeId)
assertTradeExists(nodeAApi, nodeBParty, testTradeId)
assertThat(runValuationsBetween(nodeAApi, nodeBParty)).isTrue()
assertValuationExists(nodeBApi, nodeAParty)
assertValuationExists(nodeAApi, nodeBParty)
}
}
@ -58,17 +62,17 @@ class SimmValuationTest : IntegrationTestCategory {
return partyApi.putJson("${counterparty.id}/trades", trade)
}
private fun tradeExists(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty, tradeId: String): Boolean {
private fun assertTradeExists(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty, tradeId: String) {
val trades = partyApi.getJson<Array<SwapDataView>>("${counterparty.id}/trades")
return (trades.find { it.id == tradeId } != null)
assertThat(trades).filteredOn { it.id == tradeId }.isNotEmpty()
}
private fun runValuationsBetween(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
return partyApi.postJson("${counterparty.id}/portfolio/valuations/calculate", PortfolioApi.ValuationCreationParams(valuationDate))
}
private fun valuationExists(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty): Boolean {
private fun assertValuationExists(partyApi: HttpApi, counterparty: PortfolioApi.ApiParty) {
val valuations = partyApi.getJson<PortfolioApiUtils.ValuationsView>("${counterparty.id}/portfolio/valuations")
return (valuations.initialMargin.call["total"] != 0.0)
assertThat(valuations.initialMargin.call["total"]).isNotEqualTo(0.0)
}
}

View File

@ -34,6 +34,7 @@ configurations {
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:${assertj_version}"
// Corda integration dependencies
runtime project(path: ":node:capsule", configuration: 'runtimeArtifacts')

View File

@ -2,6 +2,7 @@ package net.corda.traderdemo
import com.google.common.util.concurrent.Futures
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.contracts.DOLLARS
import net.corda.core.getOrThrow
import net.corda.core.node.services.ServiceInfo
import net.corda.core.utilities.DUMMY_BANK_A
@ -13,6 +14,8 @@ import net.corda.node.services.transactions.SimpleNotaryService
import net.corda.nodeapi.User
import net.corda.testing.BOC
import net.corda.testing.node.NodeBasedTest
import net.corda.traderdemo.flow.SellerFlow
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
class TraderDemoTest : NodeBasedTest() {
@ -20,7 +23,7 @@ class TraderDemoTest : NodeBasedTest() {
fun `runs trader demo`() {
val permissions = setOf(
startFlowPermission<IssuerFlow.IssuanceRequester>(),
startFlowPermission<net.corda.traderdemo.flow.SellerFlow>())
startFlowPermission<SellerFlow>())
val demoUser = listOf(User("demo", "demo", permissions))
val user = User("user1", "test", permissions = setOf(startFlowPermission<IssuerFlow.IssuanceRequester>()))
val (nodeA, nodeB) = Futures.allAsList(
@ -35,7 +38,21 @@ class TraderDemoTest : NodeBasedTest() {
client.start(demoUser[0].username, demoUser[0].password).proxy()
}
TraderDemoClientApi(nodeARpc).runBuyer()
TraderDemoClientApi(nodeBRpc).runSeller(counterparty = nodeA.info.legalIdentity.name)
val clientA = TraderDemoClientApi(nodeARpc)
val clientB = TraderDemoClientApi(nodeBRpc)
val originalACash = clientA.cashCount // A has random number of issued amount
val expectedBCash = clientB.cashCount + 1
val expectedPaper = listOf(clientA.commercialPaperCount + 1, clientB.commercialPaperCount)
clientA.runBuyer(amount = 100.DOLLARS)
clientB.runSeller(counterparty = nodeA.info.legalIdentity.name, amount = 5.DOLLARS)
val actualPaper = listOf(clientA.commercialPaperCount, clientB.commercialPaperCount)
assertThat(clientA.cashCount).isGreaterThan(originalACash)
assertThat(clientB.cashCount).isEqualTo(expectedBCash)
assertThat(actualPaper).isEqualTo(expectedPaper)
assertThat(clientA.dollarCashBalance).isEqualTo(95.DOLLARS)
assertThat(clientB.dollarCashBalance).isEqualTo(5.DOLLARS)
}
}

View File

@ -1,9 +1,13 @@
package net.corda.traderdemo
import com.google.common.util.concurrent.Futures
import net.corda.contracts.CommercialPaper
import net.corda.contracts.asset.Cash
import net.corda.contracts.testing.calculateRandomlySizedAmounts
import net.corda.core.contracts.Amount
import net.corda.core.contracts.DOLLARS
import net.corda.core.contracts.USD
import net.corda.core.contracts.filterStatesOfType
import net.corda.core.getOrThrow
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.messaging.startFlow
@ -24,6 +28,12 @@ class TraderDemoClientApi(val rpc: CordaRPCOps) {
val logger = loggerFor<TraderDemoClientApi>()
}
val cashCount: Int get() = rpc.vaultAndUpdates().first.filterStatesOfType<Cash.State>().size
val dollarCashBalance: Amount<Currency> get() = rpc.getCashBalances()[USD]!!
val commercialPaperCount: Int get() = rpc.vaultAndUpdates().first.filterStatesOfType<CommercialPaper.State>().size
fun runBuyer(amount: Amount<Currency> = 30000.DOLLARS) {
val bankOfCordaParty = rpc.partyFromName(BOC.name)
?: throw Exception("Unable to locate ${BOC.name} in Network Map Service")

View File

@ -18,6 +18,7 @@ import net.corda.nodeapi.User
import net.corda.nodeapi.config.parseAs
import net.corda.testing.MOCK_NODE_VERSION_INFO
import net.corda.testing.getFreeLocalPorts
import org.apache.logging.log4j.Level
import org.junit.After
import org.junit.Rule
import org.junit.rules.TemporaryFolder
@ -39,6 +40,10 @@ abstract class NodeBasedTest {
val networkMapNode: Node get() = _networkMapNode ?: startNetworkMapNode()
init {
System.setProperty("consoleLogLevel", Level.DEBUG.name().toLowerCase())
}
/**
* Stops the network map node and all the nodes started by [startNode]. This is called automatically after each test
* but can also be called manually within a test.