mirror of
https://github.com/corda/corda.git
synced 2025-01-31 00:24:59 +00:00
Add a mock Node implementation to simplify unit testing.
This commit is contained in:
parent
5bd8a3408b
commit
cb52ff09b8
@ -24,7 +24,7 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
// TODO: Refactor this test some more to cut down on messy setup duplication.
|
||||
// TODO: Refactor this test to use the MockNode class, which will clean this file up significantly.
|
||||
|
||||
/**
|
||||
* In this example, Alice wishes to sell her commercial paper to Bob in return for $1,000,000 and they wish to do
|
||||
|
104
src/test/kotlin/core/node/MockNode.kt
Normal file
104
src/test/kotlin/core/node/MockNode.kt
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2015 Distributed Ledger Group LLC. Distributed as Licensed Company IP to DLG Group Members
|
||||
* pursuant to the August 7, 2015 Advisory Services Agreement and subject to the Company IP License terms
|
||||
* set forth therein.
|
||||
*
|
||||
* All other rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2015 Distributed Ledger Group LLC. Distributed as Licensed Company IP to DLG Group Members
|
||||
* pursuant to the August 7, 2015 Advisory Services Agreement and subject to the Company IP License terms
|
||||
* set forth therein.
|
||||
*
|
||||
* All other rights reserved.
|
||||
*/
|
||||
|
||||
package core.node
|
||||
|
||||
import com.google.common.jimfs.Jimfs
|
||||
import com.google.common.util.concurrent.MoreExecutors
|
||||
import core.messaging.InMemoryMessagingNetwork
|
||||
import core.messaging.LegallyIdentifiableNode
|
||||
import core.messaging.MessagingService
|
||||
import core.utilities.loggerFor
|
||||
import org.slf4j.Logger
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import java.util.concurrent.ExecutorService
|
||||
|
||||
/**
|
||||
* A mock node brings up a suite of in-memory services in a fast manner suitable for unit testing.
|
||||
* Components that do IO are either swapped out for mocks, or pointed to a [Jimfs] in memory filesystem.
|
||||
*
|
||||
* Mock network nodes require manual pumping by default: they will not run asynchronous. This means that
|
||||
* for message exchanges to take place (and associated handlers to run), you must call the [runNetwork]
|
||||
* method.
|
||||
*/
|
||||
class MockNetwork {
|
||||
private var counter = 0
|
||||
val filesystem = Jimfs.newFileSystem()
|
||||
val messagingNetwork = InMemoryMessagingNetwork()
|
||||
|
||||
private val _nodes = ArrayList<MockNode>()
|
||||
/** A read only view of the current set of executing nodes. */
|
||||
val nodes: List<MockNode> = _nodes
|
||||
|
||||
init {
|
||||
Files.createDirectory(filesystem.getPath("/nodes"))
|
||||
}
|
||||
|
||||
open class MockNode(dir: Path, config: NodeConfiguration, val network: InMemoryMessagingNetwork,
|
||||
withTimestamper: LegallyIdentifiableNode?) : AbstractNode(dir, config, withTimestamper) {
|
||||
override val log: Logger = loggerFor<MockNode>()
|
||||
override val serverThread: ExecutorService = MoreExecutors.newDirectExecutorService()
|
||||
|
||||
// We only need to override the messaging service here, as currently everything that hits disk does so
|
||||
// through the java.nio API which we are already mocking via Jimfs.
|
||||
|
||||
override fun makeMessagingService(): MessagingService {
|
||||
return network.createNode(true).second.start().get()
|
||||
}
|
||||
|
||||
override fun start(): MockNode {
|
||||
super.start()
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
fun createNode(withTimestamper: LegallyIdentifiableNode?,
|
||||
factory: (Path, NodeConfiguration, network: InMemoryMessagingNetwork, LegallyIdentifiableNode?) -> MockNode = { p, n, n2, l -> MockNode(p, n, n2, l) }): MockNode {
|
||||
val path = filesystem.getPath("/nodes/$counter")
|
||||
Files.createDirectory(path)
|
||||
val config = object : NodeConfiguration {
|
||||
override val myLegalName: String = "Mock Company $counter"
|
||||
}
|
||||
val node = factory(path, config, messagingNetwork, withTimestamper).start()
|
||||
_nodes.add(node)
|
||||
counter++
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks every node in order to process any queued up inbound messages. This may in turn result in nodes
|
||||
* sending more messages to each other, thus, a typical usage is to call runNetwork with the [rounds]
|
||||
* parameter set to -1 (the default) which simply runs as many rounds as necessary to result in network
|
||||
* stability (no nodes sent any messages in the last round).
|
||||
*/
|
||||
fun runNetwork(rounds: Int = -1) {
|
||||
fun pumpAll() = messagingNetwork.endpoints.map { it.pump(false) }
|
||||
if (rounds == -1)
|
||||
while (pumpAll().any { it }) {}
|
||||
else
|
||||
repeat(rounds) { pumpAll() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a two node network in which the first node runs a timestamping service and the other doesn't.
|
||||
*/
|
||||
fun createTwoNodes(): Pair<MockNode, MockNode> {
|
||||
require(nodes.isEmpty())
|
||||
return Pair(createNode(null), createNode(nodes[0].legallyIdentifableAddress))
|
||||
}
|
||||
}
|
@ -27,6 +27,8 @@ import java.time.ZoneId
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
// TODO: Refactor this to use MockNode.
|
||||
|
||||
class TimestamperNodeServiceTest : TestWithInMemoryNetwork() {
|
||||
lateinit var myMessaging: Pair<InMemoryMessagingNetwork.Handle, InMemoryMessagingNetwork.InMemoryMessaging>
|
||||
lateinit var serviceMessaging: Pair<InMemoryMessagingNetwork.Handle, InMemoryMessagingNetwork.InMemoryMessaging>
|
||||
|
Loading…
x
Reference in New Issue
Block a user