mirror of
https://github.com/corda/corda.git
synced 2024-12-21 05:53:23 +00:00
INFRA-604: Switch tests to use database snapshots (#6671)
Created a database snapshot of a clean Corda OS 4.5.1 database, which can now be used for testing by both the node driver and mock network. The MockNetwork was changed from using an in memory database to using an on disk database, and makes use of the snapshot to speed up setup times. The Node Driver was changed from defaulting to an in-memory database to defaulting to an on-disk database. Tests that do not specify the type of database to use will thus use an on-disk database. Tests that opt in for an in-memory database will continue to use an in-memory database as before. The database snapshots are copied to the node directory inside the build folder, therefore, they should be cleaned up after a build. Co-authored-by: Ross Nicoll <ross.nicoll@r3.com>
This commit is contained in:
parent
9962c9085d
commit
e562c5828b
@ -50,7 +50,8 @@ class H2SecurityTests {
|
|||||||
inMemoryDB = false,
|
inMemoryDB = false,
|
||||||
startNodesInProcess = false,
|
startNodesInProcess = false,
|
||||||
notarySpecs = emptyList(),
|
notarySpecs = emptyList(),
|
||||||
cordappsForAllNodes = emptyList()
|
cordappsForAllNodes = emptyList(),
|
||||||
|
premigrateH2Database = false
|
||||||
)) {
|
)) {
|
||||||
val port = getFreePort()
|
val port = getFreePort()
|
||||||
startNode(customOverrides = mapOf(h2AddressKey to "localhost:$port", dbPasswordKey to "x")).getOrThrow()
|
startNode(customOverrides = mapOf(h2AddressKey to "localhost:$port", dbPasswordKey to "x")).getOrThrow()
|
||||||
@ -71,7 +72,8 @@ class H2SecurityTests {
|
|||||||
inMemoryDB = false,
|
inMemoryDB = false,
|
||||||
startNodesInProcess = false,
|
startNodesInProcess = false,
|
||||||
notarySpecs = emptyList(),
|
notarySpecs = emptyList(),
|
||||||
cordappsForAllNodes = listOf(enclosedCordapp())
|
cordappsForAllNodes = listOf(enclosedCordapp()),
|
||||||
|
premigrateH2Database = false
|
||||||
)) {
|
)) {
|
||||||
val port = getFreePort()
|
val port = getFreePort()
|
||||||
val nodeHandle = startNode(rpcUsers = listOf(user), customOverrides = mapOf(h2AddressKey to "localhost:$port",
|
val nodeHandle = startNode(rpcUsers = listOf(user), customOverrides = mapOf(h2AddressKey to "localhost:$port",
|
||||||
|
@ -82,7 +82,8 @@ class LargeTransactionsTest {
|
|||||||
driver(DriverParameters(
|
driver(DriverParameters(
|
||||||
startNodesInProcess = true,
|
startNodesInProcess = true,
|
||||||
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()),
|
cordappsForAllNodes = listOf(DUMMY_CONTRACTS_CORDAPP, enclosedCordapp()),
|
||||||
networkParameters = testNetworkParameters(maxMessageSize = 15.MB.toInt(), maxTransactionSize = 13.MB.toInt())
|
networkParameters = testNetworkParameters(maxMessageSize = 15.MB.toInt(), maxTransactionSize = 13.MB.toInt()),
|
||||||
|
premigrateH2Database = false
|
||||||
)) {
|
)) {
|
||||||
val rpcUser = User("admin", "admin", setOf("ALL"))
|
val rpcUser = User("admin", "admin", setOf("ALL"))
|
||||||
val (alice, _) = listOf(ALICE_NAME, BOB_NAME).map { startNode(providedName = it, rpcUsers = listOf(rpcUser)) }.transpose().getOrThrow()
|
val (alice, _) = listOf(ALICE_NAME, BOB_NAME).map { startNode(providedName = it, rpcUsers = listOf(rpcUser)) }.transpose().getOrThrow()
|
||||||
|
@ -43,21 +43,28 @@ data class NotaryHandle(val identity: Party, val validating: Boolean, val nodeHa
|
|||||||
interface NodeHandle : AutoCloseable {
|
interface NodeHandle : AutoCloseable {
|
||||||
/** Get the [NodeInfo] for this node */
|
/** Get the [NodeInfo] for this node */
|
||||||
val nodeInfo: NodeInfo
|
val nodeInfo: NodeInfo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface to the node's RPC system. The first RPC user will be used to login if are any, otherwise a default one
|
* Interface to the node's RPC system. The first RPC user will be used to login if are any, otherwise a default one
|
||||||
* will be added and that will be used.
|
* will be added and that will be used.
|
||||||
*/
|
*/
|
||||||
val rpc: CordaRPCOps
|
val rpc: CordaRPCOps
|
||||||
|
|
||||||
/** Get the p2p address for this node **/
|
/** Get the p2p address for this node **/
|
||||||
val p2pAddress: NetworkHostAndPort
|
val p2pAddress: NetworkHostAndPort
|
||||||
|
|
||||||
/** Get the rpc address for this node **/
|
/** Get the rpc address for this node **/
|
||||||
val rpcAddress: NetworkHostAndPort
|
val rpcAddress: NetworkHostAndPort
|
||||||
|
|
||||||
/** Get the rpc admin address for this node **/
|
/** Get the rpc admin address for this node **/
|
||||||
val rpcAdminAddress: NetworkHostAndPort
|
val rpcAdminAddress: NetworkHostAndPort
|
||||||
|
|
||||||
/** Get the JMX server address for this node, if JMX is enabled **/
|
/** Get the JMX server address for this node, if JMX is enabled **/
|
||||||
val jmxAddress: NetworkHostAndPort?
|
val jmxAddress: NetworkHostAndPort?
|
||||||
|
|
||||||
/** Get a [List] of [User]'s for this node **/
|
/** Get a [List] of [User]'s for this node **/
|
||||||
val rpcUsers: List<User>
|
val rpcUsers: List<User>
|
||||||
|
|
||||||
/** The location of the node's base directory **/
|
/** The location of the node's base directory **/
|
||||||
val baseDirectory: Path
|
val baseDirectory: Path
|
||||||
|
|
||||||
@ -67,7 +74,8 @@ interface NodeHandle : AutoCloseable {
|
|||||||
fun stop()
|
fun stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun NodeHandle.logFile(): File = (baseDirectory / "logs").toFile().walk().filter { it.name.startsWith("node-") && it.extension == "log" }.single()
|
fun NodeHandle.logFile(): File = (baseDirectory / "logs").toFile().walk().filter { it.name.startsWith("node-") && it.extension == "log" }
|
||||||
|
.single()
|
||||||
|
|
||||||
/** Interface which represents an out of process node and exposes its process handle. **/
|
/** Interface which represents an out of process node and exposes its process handle. **/
|
||||||
@DoNotImplement
|
@DoNotImplement
|
||||||
@ -91,7 +99,8 @@ interface InProcess : NodeHandle {
|
|||||||
* Starts an already constructed flow. Note that you must be on the server thread to call this method.
|
* Starts an already constructed flow. Note that you must be on the server thread to call this method.
|
||||||
* @param context indicates who started the flow, see: [InvocationContext].
|
* @param context indicates who started the flow, see: [InvocationContext].
|
||||||
*/
|
*/
|
||||||
fun <T> startFlow(logic: FlowLogic<T>): CordaFuture<T> = internalServices.startFlow(logic, internalServices.newContext()).getOrThrow().resultFuture
|
fun <T> startFlow(logic: FlowLogic<T>): CordaFuture<T> = internalServices.startFlow(logic, internalServices.newContext())
|
||||||
|
.getOrThrow().resultFuture
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,7 +215,8 @@ fun <A> driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr
|
|||||||
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
|
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
|
||||||
djvmCordaSource = defaultParameters.djvmCordaSource,
|
djvmCordaSource = defaultParameters.djvmCordaSource,
|
||||||
environmentVariables = defaultParameters.environmentVariables,
|
environmentVariables = defaultParameters.environmentVariables,
|
||||||
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema
|
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema,
|
||||||
|
premigrateH2Database = defaultParameters.premigrateH2Database
|
||||||
),
|
),
|
||||||
coerce = { it },
|
coerce = { it },
|
||||||
dsl = dsl
|
dsl = dsl
|
||||||
@ -245,6 +255,8 @@ fun <A> driver(defaultParameters: DriverParameters = DriverParameters(), dsl: Dr
|
|||||||
* @property cordappsForAllNodes [TestCordapp]s that will be added to each node started by the [DriverDSL].
|
* @property cordappsForAllNodes [TestCordapp]s that will be added to each node started by the [DriverDSL].
|
||||||
* @property djvmBootstrapSource Location of a JAR containing the Java APIs for the DJVM to use.
|
* @property djvmBootstrapSource Location of a JAR containing the Java APIs for the DJVM to use.
|
||||||
* @property djvmCordaSource Locations of JARs of user-supplied classes to execute within the DJVM sandbox.
|
* @property djvmCordaSource Locations of JARs of user-supplied classes to execute within the DJVM sandbox.
|
||||||
|
* @property premigrateH2Database Whether to use a prebuilt H2 database schema or start from an empty schema.
|
||||||
|
* This can save time for tests which do not need to migrate from a blank schema.
|
||||||
*/
|
*/
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
data class DriverParameters(
|
data class DriverParameters(
|
||||||
@ -263,12 +275,13 @@ data class DriverParameters(
|
|||||||
@Suppress("DEPRECATION") val jmxPolicy: JmxPolicy = JmxPolicy(),
|
@Suppress("DEPRECATION") val jmxPolicy: JmxPolicy = JmxPolicy(),
|
||||||
val networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()),
|
val networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()),
|
||||||
val notaryCustomOverrides: Map<String, Any?> = emptyMap(),
|
val notaryCustomOverrides: Map<String, Any?> = emptyMap(),
|
||||||
val inMemoryDB: Boolean = true,
|
val inMemoryDB: Boolean = false,
|
||||||
val cordappsForAllNodes: Collection<TestCordapp>? = null,
|
val cordappsForAllNodes: Collection<TestCordapp>? = null,
|
||||||
val djvmBootstrapSource: Path? = null,
|
val djvmBootstrapSource: Path? = null,
|
||||||
val djvmCordaSource: List<Path> = emptyList(),
|
val djvmCordaSource: List<Path> = emptyList(),
|
||||||
val environmentVariables: Map<String, String> = emptyMap(),
|
val environmentVariables: Map<String, String> = emptyMap(),
|
||||||
val allowHibernateToManageAppSchema: Boolean = true
|
val allowHibernateToManageAppSchema: Boolean = true,
|
||||||
|
val premigrateH2Database: Boolean = true
|
||||||
) {
|
) {
|
||||||
constructor(cordappsForAllNodes: Collection<TestCordapp>) : this(isDebug = false, cordappsForAllNodes = cordappsForAllNodes)
|
constructor(cordappsForAllNodes: Collection<TestCordapp>) : this(isDebug = false, cordappsForAllNodes = cordappsForAllNodes)
|
||||||
|
|
||||||
@ -376,6 +389,49 @@ data class DriverParameters(
|
|||||||
cordappsForAllNodes = null
|
cordappsForAllNodes = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
isDebug: Boolean = false,
|
||||||
|
driverDirectory: Path = Paths.get("build") / "node-driver" / getTimestampAsDirectoryName(),
|
||||||
|
portAllocation: PortAllocation = incrementalPortAllocation(),
|
||||||
|
debugPortAllocation: PortAllocation = incrementalPortAllocation(),
|
||||||
|
systemProperties: Map<String, String> = emptyMap(),
|
||||||
|
useTestClock: Boolean = false,
|
||||||
|
startNodesInProcess: Boolean = false,
|
||||||
|
waitForAllNodesToFinish: Boolean = false,
|
||||||
|
notarySpecs: List<NotarySpec> = listOf(NotarySpec(DUMMY_NOTARY_NAME)),
|
||||||
|
extraCordappPackagesToScan: List<String> = emptyList(),
|
||||||
|
@Suppress("DEPRECATION") jmxPolicy: JmxPolicy = JmxPolicy(),
|
||||||
|
networkParameters: NetworkParameters = testNetworkParameters(notaries = emptyList()),
|
||||||
|
notaryCustomOverrides: Map<String, Any?> = emptyMap(),
|
||||||
|
inMemoryDB: Boolean = false,
|
||||||
|
cordappsForAllNodes: Collection<TestCordapp>? = null,
|
||||||
|
djvmBootstrapSource: Path? = null,
|
||||||
|
djvmCordaSource: List<Path> = emptyList(),
|
||||||
|
environmentVariables: Map<String, String> = emptyMap(),
|
||||||
|
allowHibernateToManageAppSchema: Boolean = true
|
||||||
|
) : this(
|
||||||
|
isDebug,
|
||||||
|
driverDirectory,
|
||||||
|
portAllocation,
|
||||||
|
debugPortAllocation,
|
||||||
|
systemProperties,
|
||||||
|
useTestClock,
|
||||||
|
startNodesInProcess,
|
||||||
|
waitForAllNodesToFinish,
|
||||||
|
notarySpecs,
|
||||||
|
extraCordappPackagesToScan,
|
||||||
|
jmxPolicy,
|
||||||
|
networkParameters,
|
||||||
|
notaryCustomOverrides,
|
||||||
|
inMemoryDB,
|
||||||
|
cordappsForAllNodes,
|
||||||
|
djvmBootstrapSource,
|
||||||
|
djvmCordaSource,
|
||||||
|
environmentVariables,
|
||||||
|
allowHibernateToManageAppSchema,
|
||||||
|
premigrateH2Database = true
|
||||||
|
)
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
isDebug: Boolean,
|
isDebug: Boolean,
|
||||||
driverDirectory: Path,
|
driverDirectory: Path,
|
||||||
@ -417,6 +473,7 @@ data class DriverParameters(
|
|||||||
fun withStartNodesInProcess(startNodesInProcess: Boolean): DriverParameters = copy(startNodesInProcess = startNodesInProcess)
|
fun withStartNodesInProcess(startNodesInProcess: Boolean): DriverParameters = copy(startNodesInProcess = startNodesInProcess)
|
||||||
fun withWaitForAllNodesToFinish(waitForAllNodesToFinish: Boolean): DriverParameters = copy(waitForAllNodesToFinish = waitForAllNodesToFinish)
|
fun withWaitForAllNodesToFinish(waitForAllNodesToFinish: Boolean): DriverParameters = copy(waitForAllNodesToFinish = waitForAllNodesToFinish)
|
||||||
fun withNotarySpecs(notarySpecs: List<NotarySpec>): DriverParameters = copy(notarySpecs = notarySpecs)
|
fun withNotarySpecs(notarySpecs: List<NotarySpec>): DriverParameters = copy(notarySpecs = notarySpecs)
|
||||||
|
|
||||||
@Deprecated("extraCordappPackagesToScan does not preserve the original CorDapp's versioning and metadata, which may lead to " +
|
@Deprecated("extraCordappPackagesToScan does not preserve the original CorDapp's versioning and metadata, which may lead to " +
|
||||||
"misleading results in tests. Use withCordappsForAllNodes instead.")
|
"misleading results in tests. Use withCordappsForAllNodes instead.")
|
||||||
fun withExtraCordappPackagesToScan(extraCordappPackagesToScan: List<String>): DriverParameters = copy(extraCordappPackagesToScan = extraCordappPackagesToScan)
|
fun withExtraCordappPackagesToScan(extraCordappPackagesToScan: List<String>): DriverParameters = copy(extraCordappPackagesToScan = extraCordappPackagesToScan)
|
||||||
@ -530,4 +587,48 @@ data class DriverParameters(
|
|||||||
djvmCordaSource = djvmCordaSource,
|
djvmCordaSource = djvmCordaSource,
|
||||||
environmentVariables = environmentVariables
|
environmentVariables = environmentVariables
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Legacy copy() from v4.5
|
||||||
|
@Suppress("LongParameterList")
|
||||||
|
fun copy(isDebug: Boolean,
|
||||||
|
driverDirectory: Path,
|
||||||
|
portAllocation: PortAllocation,
|
||||||
|
debugPortAllocation: PortAllocation,
|
||||||
|
systemProperties: Map<String, String>,
|
||||||
|
useTestClock: Boolean,
|
||||||
|
startNodesInProcess: Boolean,
|
||||||
|
waitForAllNodesToFinish: Boolean,
|
||||||
|
notarySpecs: List<NotarySpec>,
|
||||||
|
extraCordappPackagesToScan: List<String>,
|
||||||
|
@Suppress("DEPRECATION") jmxPolicy: JmxPolicy,
|
||||||
|
networkParameters: NetworkParameters,
|
||||||
|
notaryCustomOverrides: Map<String, Any?>,
|
||||||
|
inMemoryDB: Boolean,
|
||||||
|
cordappsForAllNodes: Collection<TestCordapp>?,
|
||||||
|
djvmBootstrapSource: Path?,
|
||||||
|
djvmCordaSource: List<Path>,
|
||||||
|
environmentVariables: Map<String, String>,
|
||||||
|
allowHibernateToManageAppSchema: Boolean
|
||||||
|
) = this.copy(
|
||||||
|
isDebug = isDebug,
|
||||||
|
driverDirectory = driverDirectory,
|
||||||
|
portAllocation = portAllocation,
|
||||||
|
debugPortAllocation = debugPortAllocation,
|
||||||
|
systemProperties = systemProperties,
|
||||||
|
useTestClock = useTestClock,
|
||||||
|
startNodesInProcess = startNodesInProcess,
|
||||||
|
waitForAllNodesToFinish = waitForAllNodesToFinish,
|
||||||
|
notarySpecs = notarySpecs,
|
||||||
|
extraCordappPackagesToScan = extraCordappPackagesToScan,
|
||||||
|
jmxPolicy = jmxPolicy,
|
||||||
|
networkParameters = networkParameters,
|
||||||
|
notaryCustomOverrides = notaryCustomOverrides,
|
||||||
|
inMemoryDB = inMemoryDB,
|
||||||
|
cordappsForAllNodes = cordappsForAllNodes,
|
||||||
|
djvmBootstrapSource = djvmBootstrapSource,
|
||||||
|
djvmCordaSource = djvmCordaSource,
|
||||||
|
environmentVariables = environmentVariables,
|
||||||
|
allowHibernateToManageAppSchema = allowHibernateToManageAppSchema,
|
||||||
|
premigrateH2Database = true
|
||||||
|
)
|
||||||
}
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package net.corda.testing.node
|
||||||
|
|
||||||
|
import java.io.InputStream
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
|
object DatabaseSnapshot {
|
||||||
|
private const val previousCordaVersion: String = "4.5.1"
|
||||||
|
private const val databaseName: String = "persistence.mv.db"
|
||||||
|
|
||||||
|
private fun getDatabaseSnapshotStream(): InputStream {
|
||||||
|
val resourceUri = this::class.java.getResource("/databasesnapshots/${previousCordaVersion}/$databaseName")
|
||||||
|
return resourceUri.openStream()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun copyDatabaseSnapshot(baseDirectory: Path) {
|
||||||
|
getDatabaseSnapshotStream().use { stream ->
|
||||||
|
Files.createDirectories(baseDirectory)
|
||||||
|
val path = baseDirectory.resolve(databaseName)
|
||||||
|
Files.copy(stream, path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -48,6 +48,7 @@ import net.corda.testing.internal.configureDatabase
|
|||||||
import net.corda.testing.node.internal.*
|
import net.corda.testing.node.internal.*
|
||||||
import net.corda.testing.services.MockAttachmentStorage
|
import net.corda.testing.services.MockAttachmentStorage
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.nio.file.Paths
|
||||||
import java.security.KeyPair
|
import java.security.KeyPair
|
||||||
import java.sql.Connection
|
import java.sql.Connection
|
||||||
import java.time.Clock
|
import java.time.Clock
|
||||||
@ -99,9 +100,17 @@ open class MockServices private constructor(
|
|||||||
// TODO: Can we use an X509 principal generator here?
|
// TODO: Can we use an X509 principal generator here?
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString()): Properties {
|
||||||
|
val dbDir = Paths.get("","build", "mocknetworktestdb", nodeName)
|
||||||
|
.toAbsolutePath()
|
||||||
|
val dbPath = dbDir.resolve("persistence")
|
||||||
|
try {
|
||||||
|
DatabaseSnapshot.copyDatabaseSnapshot(dbDir)
|
||||||
|
} catch (ex: java.nio.file.FileAlreadyExistsException) {
|
||||||
|
DriverDSLImpl.log.warn("Database already exists on disk, not attempting to pre-migrate database.")
|
||||||
|
}
|
||||||
val props = Properties()
|
val props = Properties()
|
||||||
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
||||||
props.setProperty("dataSource.url", "jdbc:h2:mem:${nodeName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
props.setProperty("dataSource.url", "jdbc:h2:file:$dbPath;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
||||||
props.setProperty("dataSource.user", "sa")
|
props.setProperty("dataSource.user", "sa")
|
||||||
props.setProperty("dataSource.password", "")
|
props.setProperty("dataSource.password", "")
|
||||||
return props
|
return props
|
||||||
@ -357,7 +366,6 @@ open class MockServices private constructor(
|
|||||||
constructor(cordappPackages: List<String>, initialIdentityName: CordaX500Name, identityService: IdentityService, networkParameters: NetworkParameters)
|
constructor(cordappPackages: List<String>, initialIdentityName: CordaX500Name, identityService: IdentityService, networkParameters: NetworkParameters)
|
||||||
: this(cordappPackages, TestIdentity(initialIdentityName), identityService, networkParameters)
|
: this(cordappPackages, TestIdentity(initialIdentityName), identityService, networkParameters)
|
||||||
|
|
||||||
|
|
||||||
constructor(cordappPackages: List<String>, initialIdentityName: CordaX500Name, identityService: IdentityService, networkParameters: NetworkParameters, key: KeyPair)
|
constructor(cordappPackages: List<String>, initialIdentityName: CordaX500Name, identityService: IdentityService, networkParameters: NetworkParameters, key: KeyPair)
|
||||||
: this(cordappPackages, TestIdentity(initialIdentityName, key), identityService, networkParameters)
|
: this(cordappPackages, TestIdentity(initialIdentityName, key), identityService, networkParameters)
|
||||||
|
|
||||||
@ -428,7 +436,8 @@ open class MockServices private constructor(
|
|||||||
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments).also {
|
private val mockCordappProvider: MockCordappProvider = MockCordappProvider(cordappLoader, attachments).also {
|
||||||
it.start()
|
it.start()
|
||||||
}
|
}
|
||||||
override val transactionVerifierService: TransactionVerifierService get() = InMemoryTransactionVerifierService(
|
override val transactionVerifierService: TransactionVerifierService
|
||||||
|
get() = InMemoryTransactionVerifierService(
|
||||||
numberOfWorkers = 2,
|
numberOfWorkers = 2,
|
||||||
cordappProvider = mockCordappProvider,
|
cordappProvider = mockCordappProvider,
|
||||||
attachments = attachments
|
attachments = attachments
|
||||||
|
@ -53,6 +53,7 @@ import net.corda.core.utilities.NetworkHostAndPort
|
|||||||
import net.corda.core.utilities.contextLogger
|
import net.corda.core.utilities.contextLogger
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.core.utilities.millis
|
import net.corda.core.utilities.millis
|
||||||
|
import net.corda.core.utilities.toHexString
|
||||||
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
|
import net.corda.coretesting.internal.stubs.CertificateStoreStubs
|
||||||
import net.corda.node.NodeRegistrationOption
|
import net.corda.node.NodeRegistrationOption
|
||||||
import net.corda.node.VersionInfo
|
import net.corda.node.VersionInfo
|
||||||
@ -97,6 +98,7 @@ import net.corda.testing.driver.internal.InProcessImpl
|
|||||||
import net.corda.testing.driver.internal.NodeHandleInternal
|
import net.corda.testing.driver.internal.NodeHandleInternal
|
||||||
import net.corda.testing.driver.internal.OutOfProcessImpl
|
import net.corda.testing.driver.internal.OutOfProcessImpl
|
||||||
import net.corda.testing.node.ClusterSpec
|
import net.corda.testing.node.ClusterSpec
|
||||||
|
import net.corda.testing.node.DatabaseSnapshot
|
||||||
import net.corda.testing.node.NotarySpec
|
import net.corda.testing.node.NotarySpec
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
@ -149,7 +151,8 @@ class DriverDSLImpl(
|
|||||||
val djvmBootstrapSource: Path?,
|
val djvmBootstrapSource: Path?,
|
||||||
val djvmCordaSource: List<Path>,
|
val djvmCordaSource: List<Path>,
|
||||||
val environmentVariables: Map<String, String>,
|
val environmentVariables: Map<String, String>,
|
||||||
val allowHibernateToManageAppSchema: Boolean = true
|
val allowHibernateToManageAppSchema: Boolean = true,
|
||||||
|
val premigrateH2Database: Boolean = true
|
||||||
) : InternalDriverDSL {
|
) : InternalDriverDSL {
|
||||||
|
|
||||||
private var _executorService: ScheduledExecutorService? = null
|
private var _executorService: ScheduledExecutorService? = null
|
||||||
@ -195,7 +198,7 @@ class DriverDSLImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun NodeConfig.checkAndOverrideForInMemoryDB(): NodeConfig = this.run {
|
private fun NodeConfig.checkAndOverrideForInMemoryDB(): NodeConfig = this.run {
|
||||||
if (inMemoryDB && corda.dataSourceProperties.getProperty("dataSource.url").startsWith("jdbc:h2:")) {
|
if (inMemoryDB && isH2Database(corda)) {
|
||||||
val jdbcUrl = "jdbc:h2:mem:persistence${inMemoryCounter.getAndIncrement()};DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=100"
|
val jdbcUrl = "jdbc:h2:mem:persistence${inMemoryCounter.getAndIncrement()};DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000;WRITE_DELAY=100"
|
||||||
corda.dataSourceProperties.setProperty("dataSource.url", jdbcUrl)
|
corda.dataSourceProperties.setProperty("dataSource.url", jdbcUrl)
|
||||||
NodeConfig(typesafe + mapOf("dataSourceProperties" to mapOf("dataSource.url" to jdbcUrl)))
|
NodeConfig(typesafe + mapOf("dataSourceProperties" to mapOf("dataSource.url" to jdbcUrl)))
|
||||||
@ -269,6 +272,15 @@ class DriverDSLImpl(
|
|||||||
val name = parameters.providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB")
|
val name = parameters.providedName ?: CordaX500Name("${oneOf(names).organisation}-${p2pAddress.port}", "London", "GB")
|
||||||
|
|
||||||
val config = createConfig(name, parameters, p2pAddress)
|
val config = createConfig(name, parameters, p2pAddress)
|
||||||
|
if (premigrateH2Database && isH2Database(config)) {
|
||||||
|
if (!inMemoryDB) {
|
||||||
|
try {
|
||||||
|
DatabaseSnapshot.copyDatabaseSnapshot(config.corda.baseDirectory)
|
||||||
|
} catch (ex: java.nio.file.FileAlreadyExistsException) {
|
||||||
|
log.warn("Database already exists on disk, not attempting to pre-migrate database.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
val registrationFuture = if (compatibilityZone?.rootCert != null) {
|
val registrationFuture = if (compatibilityZone?.rootCert != null) {
|
||||||
// We don't need the network map to be available to be able to register the node
|
// We don't need the network map to be available to be able to register the node
|
||||||
createSchema(config, false).flatMap { startNodeRegistration(it, compatibilityZone.rootCert, compatibilityZone.config()) }
|
createSchema(config, false).flatMap { startNodeRegistration(it, compatibilityZone.rootCert, compatibilityZone.config()) }
|
||||||
@ -1032,6 +1044,12 @@ class DriverDSLImpl(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isH2Database(config: NodeConfiguration)
|
||||||
|
= config.dataSourceProperties.getProperty("dataSource.url").startsWith("jdbc:h2:")
|
||||||
|
|
||||||
|
private fun isH2Database(config: NodeConfig)
|
||||||
|
= isH2Database(config.corda)
|
||||||
|
|
||||||
// Obvious test artifacts. This is NOT intended to be an exhaustive list!
|
// Obvious test artifacts. This is NOT intended to be an exhaustive list!
|
||||||
// It is only intended to remove those FEW jars which BLATANTLY do not
|
// It is only intended to remove those FEW jars which BLATANTLY do not
|
||||||
// belong inside a Corda Node.
|
// belong inside a Corda Node.
|
||||||
@ -1298,7 +1316,8 @@ fun <DI : DriverDSL, D : InternalDriverDSL, A> genericDriver(
|
|||||||
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
|
djvmBootstrapSource = defaultParameters.djvmBootstrapSource,
|
||||||
djvmCordaSource = defaultParameters.djvmCordaSource,
|
djvmCordaSource = defaultParameters.djvmCordaSource,
|
||||||
environmentVariables = defaultParameters.environmentVariables,
|
environmentVariables = defaultParameters.environmentVariables,
|
||||||
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema
|
allowHibernateToManageAppSchema = defaultParameters.allowHibernateToManageAppSchema,
|
||||||
|
premigrateH2Database = defaultParameters.premigrateH2Database
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val shutdownHook = addShutdownHook(driverDsl::shutdown)
|
val shutdownHook = addShutdownHook(driverDsl::shutdown)
|
||||||
@ -1397,6 +1416,7 @@ fun <A> internalDriver(
|
|||||||
djvmCordaSource: List<Path> = emptyList(),
|
djvmCordaSource: List<Path> = emptyList(),
|
||||||
environmentVariables: Map<String, String> = emptyMap(),
|
environmentVariables: Map<String, String> = emptyMap(),
|
||||||
allowHibernateToManageAppSchema: Boolean = true,
|
allowHibernateToManageAppSchema: Boolean = true,
|
||||||
|
premigrateH2Database: Boolean = true,
|
||||||
dsl: DriverDSLImpl.() -> A
|
dsl: DriverDSLImpl.() -> A
|
||||||
): A {
|
): A {
|
||||||
return genericDriver(
|
return genericDriver(
|
||||||
@ -1420,15 +1440,21 @@ fun <A> internalDriver(
|
|||||||
djvmBootstrapSource = djvmBootstrapSource,
|
djvmBootstrapSource = djvmBootstrapSource,
|
||||||
djvmCordaSource = djvmCordaSource,
|
djvmCordaSource = djvmCordaSource,
|
||||||
environmentVariables = environmentVariables,
|
environmentVariables = environmentVariables,
|
||||||
allowHibernateToManageAppSchema = allowHibernateToManageAppSchema
|
allowHibernateToManageAppSchema = allowHibernateToManageAppSchema,
|
||||||
|
premigrateH2Database = premigrateH2Database
|
||||||
),
|
),
|
||||||
coerce = { it },
|
coerce = { it },
|
||||||
dsl = dsl
|
dsl = dsl
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val DIRECTORY_TIMESTAMP_FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss.SSS").withZone(UTC)
|
||||||
|
private val directoryRandom = Random()
|
||||||
fun getTimestampAsDirectoryName(): String {
|
fun getTimestampAsDirectoryName(): String {
|
||||||
return DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss.SSS").withZone(UTC).format(Instant.now())
|
val base = DIRECTORY_TIMESTAMP_FORMAT.format(Instant.now())
|
||||||
|
// Introduce some randomness so starting two nodes in the same ms doesn't use the same path
|
||||||
|
val random = directoryRandom.nextLong().toBigInteger().toByteArray().toHexString()
|
||||||
|
return "$base-$random"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun writeConfig(path: Path, filename: String, config: Config) {
|
fun writeConfig(path: Path, filename: String, config: Config) {
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user