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_main" 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_test" 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 DEFAULT_POLL_INTERVAL = 500.millis
private const val DEFAULT_WARN_COUNT = 120
/**
* This is the interface that's exposed to DSL users.
*/
@ -102,13 +106,12 @@ interface DriverDSLExposedInterface : CordformContext {
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 dsl The dsl itself.
* @param parameters The default parameters for the driver.
* @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)
}
@ -165,16 +168,25 @@ interface DriverDSLExposedInterface : CordformContext {
* @param check The function being polled.
* @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.
* @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 }
}
/**
* 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
}
@ -345,7 +357,7 @@ fun <A> driver(
/**
* 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.
* @return The value returned in the [dsl] closure.
*/
@ -706,7 +718,7 @@ class DriverDSL(
"webAddress" to webAddress.toString(),
"networkMapService" to networkMapServiceConfigLookup(name),
"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
) + customOverrides
)
@ -883,14 +895,16 @@ class DriverDSL(
}
establishRpc(nodeConfiguration, processDeathFuture).flatMap { rpc ->
// Call waitUntilNetworkReady in background in case RPC is failing over:
val networkMapFuture = executorService.fork {
val forked = executorService.fork {
rpc.waitUntilNetworkReady()
}.flatMap { it }
}
val networkMapFuture = forked.flatMap { it }
firstOf(processDeathFuture, networkMapFuture) {
if (it == processDeathFuture) {
throw ListenProcessDeathException(nodeConfiguration.p2pAddress, process)
}
processDeathFuture.cancel(false)
log.info("Node handle is ready. NodeInfo: ${rpc.nodeInfo()}, WebAddress: ${webAddress}")
NodeHandle.OutOfProcess(rpc.nodeInfo(), rpc, nodeConfiguration, webAddress, debugPort, process)
}
}
@ -905,7 +919,7 @@ class DriverDSL(
}
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(
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.WireTransaction
import net.corda.core.utilities.OpaqueBytes
import net.corda.core.utilities.getOrThrow
import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.config.VerifierType
import net.corda.testing.ALICE
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.driver.NetworkMapStartStrategy
import org.junit.Test
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.assertNotNull
class VerifierTests {
private fun generateTransactions(number: Int): List<LedgerTransaction> {
@ -121,13 +120,16 @@ class VerifierTests {
val notaryFuture = startNotaryNode(DUMMY_NOTARY.name, verifierType = VerifierType.OutOfProcess)
val aliceNode = aliceFuture.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)!!
startVerifier(notaryNode)
notaryNode.pollUntilKnowsAbout(aliceNode).getOrThrow()
aliceNode.pollUntilKnowsAbout(notaryNode).getOrThrow()
aliceNode.rpc.startFlow(::CashIssueFlow, 10.DOLLARS, OpaqueBytes.of(0), notary).returnValue.get()
notaryNode.waitUntilNumberOfVerifiers(1)
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)
}
}
}