Attempting to make VerifierTests more stable (#1883)

* Attempting to make VerifierTests more stable

Main point: Alice node will always be faster to locate Alice by name than NotaryNode. Especially given that it may take some time
for Alice node to get reflected on the Notary's NetworkMap.

Also additional logging which might be helpful during debug and IntelliJ changed project structure reflection.

* Introduce a way for nodes to reliably learn about each other existence in the NetworkMap

Plus minor refactoring of the Driver code.
This commit is contained in:
Viktor Kolomeyko 2017-10-16 09:16:40 +01:00 committed by GitHub
parent be235673e1
commit 99b509cb68
3 changed files with 34 additions and 16 deletions

2
.idea/compiler.xml generated
View File

@ -60,6 +60,8 @@
<module name="jfx_integrationTest" target="1.8" /> <module name="jfx_integrationTest" target="1.8" />
<module name="jfx_main" target="1.8" /> <module name="jfx_main" target="1.8" />
<module name="jfx_test" target="1.8" /> <module name="jfx_test" target="1.8" />
<module name="kryo-hook_main" target="1.8" />
<module name="kryo-hook_test" target="1.8" />
<module name="loadtest_main" target="1.8" /> <module name="loadtest_main" target="1.8" />
<module name="loadtest_test" target="1.8" /> <module name="loadtest_test" target="1.8" />
<module name="mock_main" target="1.8" /> <module name="mock_main" target="1.8" />

View File

@ -67,6 +67,10 @@ import kotlin.concurrent.thread
private val log: Logger = loggerFor<DriverDSL>() private val log: Logger = loggerFor<DriverDSL>()
private val DEFAULT_POLL_INTERVAL = 500.millis
private const val DEFAULT_WARN_COUNT = 120
/** /**
* This is the interface that's exposed to DSL users. * This is the interface that's exposed to DSL users.
*/ */
@ -102,13 +106,12 @@ interface DriverDSLExposedInterface : CordformContext {
validating: Boolean = true): CordaFuture<NodeHandle> validating: Boolean = true): CordaFuture<NodeHandle>
/** /**
* Helper function for starting a [node] with custom parameters from Java. * Helper function for starting a [Node] with custom parameters from Java.
* *
* @param defaultParameters The default parameters for the driver. * @param parameters The default parameters for the driver.
* @param dsl The dsl itself.
* @return The value returned in the [dsl] closure. * @return The value returned in the [dsl] closure.
*/ */
fun <A> startNode(parameters: NodeParameters): CordaFuture<NodeHandle> { fun startNode(parameters: NodeParameters): CordaFuture<NodeHandle> {
return startNode(defaultParameters = parameters) return startNode(defaultParameters = parameters)
} }
@ -165,16 +168,25 @@ interface DriverDSLExposedInterface : CordformContext {
* @param check The function being polled. * @param check The function being polled.
* @return A future that completes with the non-null value [check] has returned. * @return A future that completes with the non-null value [check] has returned.
*/ */
fun <A> pollUntilNonNull(pollName: String, pollInterval: Duration = 500.millis, warnCount: Int = 120, check: () -> A?): CordaFuture<A> fun <A> pollUntilNonNull(pollName: String, pollInterval: Duration = DEFAULT_POLL_INTERVAL, warnCount: Int = DEFAULT_WARN_COUNT, check: () -> A?): CordaFuture<A>
/** /**
* Polls the given function until it returns true. * Polls the given function until it returns true.
* @see pollUntilNonNull * @see pollUntilNonNull
*/ */
fun pollUntilTrue(pollName: String, pollInterval: Duration = 500.millis, warnCount: Int = 120, check: () -> Boolean): CordaFuture<Unit> { fun pollUntilTrue(pollName: String, pollInterval: Duration = DEFAULT_POLL_INTERVAL, warnCount: Int = DEFAULT_WARN_COUNT, check: () -> Boolean): CordaFuture<Unit> {
return pollUntilNonNull(pollName, pollInterval, warnCount) { if (check()) Unit else null } return pollUntilNonNull(pollName, pollInterval, warnCount) { if (check()) Unit else null }
} }
/**
* Polls until a given node knows about presence of another node via its own NetworkMap
*/
fun NodeHandle.pollUntilKnowsAbout(another: NodeHandle, pollInterval: Duration = DEFAULT_POLL_INTERVAL, warnCount: Int = DEFAULT_WARN_COUNT): CordaFuture<Unit> {
return pollUntilTrue("${nodeInfo.legalIdentities} knows about ${another.nodeInfo.legalIdentities}", pollInterval, warnCount) {
another.nodeInfo in rpc.networkMapSnapshot()
}
}
val shutdownManager: ShutdownManager val shutdownManager: ShutdownManager
} }
@ -345,7 +357,7 @@ fun <A> driver(
/** /**
* Helper function for starting a [driver] with custom parameters from Java. * Helper function for starting a [driver] with custom parameters from Java.
* *
* @param defaultParameters The default parameters for the driver. * @param parameters The default parameters for the driver.
* @param dsl The dsl itself. * @param dsl The dsl itself.
* @return The value returned in the [dsl] closure. * @return The value returned in the [dsl] closure.
*/ */
@ -706,7 +718,7 @@ class DriverDSL(
"webAddress" to webAddress.toString(), "webAddress" to webAddress.toString(),
"networkMapService" to networkMapServiceConfigLookup(name), "networkMapService" to networkMapServiceConfigLookup(name),
"useTestClock" to useTestClock, "useTestClock" to useTestClock,
"rpcUsers" to if (rpcUsers.isEmpty()) defaultRpcUserList else rpcUsers.map { it.toMap() }, "rpcUsers" to if (rpcUsers.isEmpty()) defaultRpcUserList else rpcUsers.map { it.toConfig().root().unwrapped() },
"verifierType" to verifierType.name "verifierType" to verifierType.name
) + customOverrides ) + customOverrides
) )
@ -883,14 +895,16 @@ class DriverDSL(
} }
establishRpc(nodeConfiguration, processDeathFuture).flatMap { rpc -> establishRpc(nodeConfiguration, processDeathFuture).flatMap { rpc ->
// Call waitUntilNetworkReady in background in case RPC is failing over: // Call waitUntilNetworkReady in background in case RPC is failing over:
val networkMapFuture = executorService.fork { val forked = executorService.fork {
rpc.waitUntilNetworkReady() rpc.waitUntilNetworkReady()
}.flatMap { it } }
val networkMapFuture = forked.flatMap { it }
firstOf(processDeathFuture, networkMapFuture) { firstOf(processDeathFuture, networkMapFuture) {
if (it == processDeathFuture) { if (it == processDeathFuture) {
throw ListenProcessDeathException(nodeConfiguration.p2pAddress, process) throw ListenProcessDeathException(nodeConfiguration.p2pAddress, process)
} }
processDeathFuture.cancel(false) processDeathFuture.cancel(false)
log.info("Node handle is ready. NodeInfo: ${rpc.nodeInfo()}, WebAddress: ${webAddress}")
NodeHandle.OutOfProcess(rpc.nodeInfo(), rpc, nodeConfiguration, webAddress, debugPort, process) NodeHandle.OutOfProcess(rpc.nodeInfo(), rpc, nodeConfiguration, webAddress, debugPort, process)
} }
} }
@ -905,7 +919,7 @@ class DriverDSL(
} }
companion object { companion object {
private val defaultRpcUserList = listOf(User("default", "default", setOf("ALL")).toMap()) private val defaultRpcUserList = listOf(User("default", "default", setOf("ALL")).toConfig().root().unwrapped())
private val names = arrayOf( private val names = arrayOf(
ALICE.name, ALICE.name,

View File

@ -6,20 +6,19 @@ import net.corda.core.messaging.startFlow
import net.corda.core.transactions.LedgerTransaction import net.corda.core.transactions.LedgerTransaction
import net.corda.core.transactions.WireTransaction import net.corda.core.transactions.WireTransaction
import net.corda.core.utilities.OpaqueBytes import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueFlow import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.config.VerifierType import net.corda.node.services.config.VerifierType
import net.corda.testing.ALICE import net.corda.testing.ALICE
import net.corda.testing.DUMMY_NOTARY import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.chooseIdentity
import net.corda.node.services.transactions.ValidatingNotaryService
import net.corda.nodeapi.internal.ServiceInfo
import net.corda.testing.* import net.corda.testing.*
import net.corda.testing.driver.NetworkMapStartStrategy import net.corda.testing.driver.NetworkMapStartStrategy
import org.junit.Test import org.junit.Test
import java.util.* import java.util.*
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertNotNull
class VerifierTests { class VerifierTests {
private fun generateTransactions(number: Int): List<LedgerTransaction> { private fun generateTransactions(number: Int): List<LedgerTransaction> {
@ -121,13 +120,16 @@ class VerifierTests {
val notaryFuture = startNotaryNode(DUMMY_NOTARY.name, verifierType = VerifierType.OutOfProcess) val notaryFuture = startNotaryNode(DUMMY_NOTARY.name, verifierType = VerifierType.OutOfProcess)
val aliceNode = aliceFuture.get() val aliceNode = aliceFuture.get()
val notaryNode = notaryFuture.get() val notaryNode = notaryFuture.get()
val alice = notaryNode.rpc.wellKnownPartyFromX500Name(ALICE_NAME)!! val alice = aliceNode.rpc.wellKnownPartyFromX500Name(ALICE_NAME)!!
val notary = notaryNode.rpc.notaryPartyFromX500Name(DUMMY_NOTARY_SERVICE_NAME)!! val notary = notaryNode.rpc.notaryPartyFromX500Name(DUMMY_NOTARY_SERVICE_NAME)!!
startVerifier(notaryNode) startVerifier(notaryNode)
notaryNode.pollUntilKnowsAbout(aliceNode).getOrThrow()
aliceNode.pollUntilKnowsAbout(notaryNode).getOrThrow()
aliceNode.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), notary).returnValue.get() aliceNode.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), notary).returnValue.get()
notaryNode.waitUntilNumberOfVerifiers(1) notaryNode.waitUntilNumberOfVerifiers(1)
for (i in 1..10) { for (i in 1..10) {
aliceNode.rpc.startFlow(::CashPaymentFlow, 10.DOLLARS, alice).returnValue.get() val cashFlowResult = aliceNode.rpc.startFlow(::CashPaymentFlow, 10.DOLLARS, alice).returnValue.get()
assertNotNull(cashFlowResult)
} }
} }
} }