Enable integration tests to run doorman against remote database (part of ENT-1447) (#776)

Change integration tests in remote database mode infrastracture to allow passing parameterised dataSource configuration to doorman. Add doorman tables to SQL clearup scripts.
This commit is contained in:
szymonsztuka 2018-04-27 09:57:16 +01:00 committed by GitHub
parent cec2f25c67
commit df5d45a4a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 261 additions and 116 deletions

View File

@ -4274,8 +4274,6 @@ public static final class net.corda.testing.node.MockServices$Companion$makeTest
##
public final class net.corda.testing.node.MockServicesKt extends java.lang.Object
@org.jetbrains.annotations.NotNull public static final net.corda.core.serialization.SerializeAsToken createMockCordaService(net.corda.testing.node.MockServices, kotlin.jvm.functions.Function1)
@org.jetbrains.annotations.NotNull public static final com.typesafe.config.Config databaseProviderDataSourceConfig(String, String)
@org.jetbrains.annotations.NotNull public static final com.typesafe.config.Config inMemoryH2DataSourceConfig(String, String)
@org.jetbrains.annotations.NotNull public static final net.corda.node.services.identity.InMemoryIdentityService makeTestIdentityService(net.corda.core.identity.PartyAndCertificate...)
##
public static final class net.corda.testing.node.MockServicesKt$createMockCordaService$MockAppServiceHubImpl extends java.lang.Object implements net.corda.core.node.AppServiceHub, net.corda.core.node.ServiceHub

View File

@ -23,7 +23,13 @@ import net.corda.core.crypto.random63BitValue
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.nodeapi.internal.crypto.CertificateType
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.internal.makeTestDatabaseProperties
import org.junit.Before
import org.junit.ClassRule
import org.junit.Rule
import org.junit.rules.TemporaryFolder
import java.net.URL
@ -32,7 +38,7 @@ import java.util.*
import com.r3.corda.networkmanage.hsm.authentication.AuthMode as SigningServiceAuthMode
import com.r3.corda.networkmanage.hsm.generator.AuthMode as GeneratorAuthMode
abstract class HsmBaseTest {
abstract class HsmBaseTest : IntegrationTest() {
companion object {
const val ROOT_CERT_KEY_GROUP = "TEST.CORDACONNECT.ROOT"
const val NETWORK_MAP_CERT_KEY_GROUP = "TEST.CORDACONNECT.OPS.NETMAP"
@ -72,6 +78,10 @@ abstract class HsmBaseTest {
authToken = "INTEGRATION_TEST",
keyFilePassword = null))
}
@ClassRule
@JvmField
val databaseSchemas = IntegrationTestSchemas(DOORMAN_DB_NAME)
}
protected lateinit var rootKeyStoreFile: Path
@ -175,6 +185,10 @@ abstract class HsmBaseTest {
}
fun makeTestDataSourceProperties(): Properties {
return makeTestDataSourceProperties(dbName)
return makeTestDataSourceProperties(DOORMAN_DB_NAME)
}
fun makeTestDatabaseProperties(): DatabaseConfig {
return makeTestDatabaseProperties(DOORMAN_DB_NAME)
}
}

View File

@ -10,15 +10,22 @@
package com.r3.corda.networkmanage.common
import java.util.*
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import net.corda.core.crypto.SecureHash
import net.corda.testing.database.DatabaseConstants
const val HOST = "localhost"
fun makeTestDataSourceProperties(dbName: String): Properties {
val props = Properties()
props.setProperty("dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
props.setProperty("dataSource.url", "jdbc:h2:mem:$dbName;DB_CLOSE_DELAY=-1")
props.setProperty("dataSource.user", "sa")
props.setProperty("dataSource.password", "")
return props
const val DOORMAN_DB_NAME = "doorman"
fun networkMapInMemoryH2DataSourceConfig(nodeName: String? = null, postfix: String? = null) : Config {
val nodeName = nodeName ?: SecureHash.randomSHA256().toString()
val h2InstanceName = if (postfix != null) nodeName + "_" + postfix else nodeName
return ConfigFactory.parseMap(mapOf(
DatabaseConstants.DATA_SOURCE_CLASSNAME to "org.h2.jdbcx.JdbcDataSource",
DatabaseConstants.DATA_SOURCE_URL to "jdbc:h2:mem:${h2InstanceName};DB_CLOSE_DELAY=-1",
DatabaseConstants.DATA_SOURCE_USER to "sa",
DatabaseConstants.DATA_SOURCE_PASSWORD to ""))
}

View File

@ -1,6 +1,7 @@
package com.r3.corda.networkmanage.doorman
import com.r3.corda.networkmanage.common.makeTestDataSourceProperties
import com.r3.corda.networkmanage.common.DOORMAN_DB_NAME
import com.r3.corda.networkmanage.common.networkMapInMemoryH2DataSourceConfig
import com.r3.corda.networkmanage.common.utils.CertPathAndKey
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.core.crypto.random63BitValue
@ -24,6 +25,7 @@ import net.corda.testing.internal.createDevIntermediateCaCertPath
import net.corda.testing.internal.toDatabaseSchemaName
import net.corda.testing.node.internal.CompatibilityZoneParams
import net.corda.testing.node.internal.internalDriver
import net.corda.testing.node.internal.makeTestDataSourceProperties
import org.assertj.core.api.Assertions.assertThat
import org.junit.*
import org.junit.Assert.assertEquals
@ -37,7 +39,7 @@ class NetworkParametersUpdateTest : IntegrationTest() {
@ClassRule
@JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE_NAME.toDatabaseSchemaName(), BOB_NAME.toDatabaseSchemaName(),
DUMMY_NOTARY_NAME.toDatabaseSchemaName())
DUMMY_NOTARY_NAME.toDatabaseSchemaName(), DOORMAN_DB_NAME)
}
@Rule
@ -50,13 +52,14 @@ class NetworkParametersUpdateTest : IntegrationTest() {
private lateinit var rootCaCert: X509Certificate
private lateinit var doormanCa: CertificateAndKeyPair
private lateinit var networkMapCa: CertificateAndKeyPair
private lateinit var dbName: String
//for normal integration tests (not against standalone db) to create a unique db name for each tests against H2
private lateinit var dbNamePostfix: String
private var server: NetworkManagementServer? = null
@Before
fun init() {
dbName = random63BitValue().toString()
dbNamePostfix = random63BitValue().toString()
val (rootCa, doormanCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate
this.doormanCa = doormanCa
@ -149,7 +152,7 @@ class NetworkParametersUpdateTest : IntegrationTest() {
private fun startServer(startNetworkMap: Boolean = true): NetworkManagementServer {
val doormanConfig = DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis)
val server = NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true), doormanConfig, null)
val server = NetworkManagementServer(makeTestDataSourceProperties(DOORMAN_DB_NAME, dbNamePostfix, fallBackConfigSupplier = ::networkMapInMemoryH2DataSourceConfig), DatabaseConfig(runMigration = true), doormanConfig, null)
server.start(
serverAddress,
CertPathAndKey(listOf(doormanCa.certificate, rootCaCert), doormanCa.keyPair.private),
@ -168,7 +171,7 @@ class NetworkParametersUpdateTest : IntegrationTest() {
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
server?.close()
NetworkManagementServer(
makeTestDataSourceProperties(dbName),
makeTestDataSourceProperties(DOORMAN_DB_NAME, dbNamePostfix, fallBackConfigSupplier = ::networkMapInMemoryH2DataSourceConfig),
DatabaseConfig(runMigration = true),
DoormanConfig(approveAll = true, jira = null, approveInterval = timeoutMillis),
null).use {

View File

@ -10,7 +10,8 @@
package com.r3.corda.networkmanage.doorman
import com.r3.corda.networkmanage.common.makeTestDataSourceProperties
import com.r3.corda.networkmanage.common.DOORMAN_DB_NAME
import com.r3.corda.networkmanage.common.networkMapInMemoryH2DataSourceConfig
import com.r3.corda.networkmanage.common.utils.CertPathAndKey
import com.r3.corda.networkmanage.doorman.signer.LocalSigner
import net.corda.cordform.CordformNode
@ -27,7 +28,6 @@ import net.corda.finance.DOLLARS
import net.corda.finance.flows.CashIssueAndPaymentFlow
import net.corda.nodeapi.internal.createDevNetworkMapCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.core.singleIdentity
import net.corda.testing.driver.NodeHandle
@ -39,6 +39,8 @@ import net.corda.testing.internal.createDevIntermediateCaCertPath
import net.corda.testing.node.NotarySpec
import net.corda.testing.node.internal.CompatibilityZoneParams
import net.corda.testing.node.internal.internalDriver
import net.corda.testing.node.internal.makeTestDataSourceProperties
import net.corda.testing.node.internal.makeTestDatabaseProperties
import org.assertj.core.api.Assertions.assertThat
import org.junit.*
import java.net.URL
@ -56,7 +58,8 @@ class NodeRegistrationTest : IntegrationTest() {
@ClassRule
@JvmField
val databaseSchemas = IntegrationTestSchemas(notaryName.organisation, aliceName.organisation, genevieveName.organisation)
val databaseSchemas = IntegrationTestSchemas(notaryName.organisation, aliceName.organisation, genevieveName.organisation,
DOORMAN_DB_NAME)
}
@Rule
@ -69,7 +72,8 @@ class NodeRegistrationTest : IntegrationTest() {
private lateinit var rootCaCert: X509Certificate
private lateinit var doormanCa: CertificateAndKeyPair
private lateinit var networkMapCa: CertificateAndKeyPair
private lateinit var dbName: String
//for normal integration tests (not against standalone db) to create a unique db name for each tests against H2
private lateinit var dbNamePostfix: String
private var server: NetworkManagementServer? = null
@ -87,7 +91,7 @@ class NodeRegistrationTest : IntegrationTest() {
@Before
fun init() {
dbName = random63BitValue().toString()
dbNamePostfix = random63BitValue().toString()
val (rootCa, doormanCa) = createDevIntermediateCaCertPath()
rootCaCert = rootCa.certificate
this.doormanCa = doormanCa
@ -168,7 +172,7 @@ class NodeRegistrationTest : IntegrationTest() {
}
private fun startServer(startNetworkMap: Boolean = true): NetworkManagementServer {
val server = NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig)
val server = NetworkManagementServer(makeTestDataSourceProperties(DOORMAN_DB_NAME, dbNamePostfix, fallBackConfigSupplier = ::networkMapInMemoryH2DataSourceConfig), makeTestDatabaseProperties(DOORMAN_DB_NAME), doormanConfig, revocationConfig)
server.start(
serverAddress,
CertPathAndKey(listOf(doormanCa.certificate, rootCaCert), doormanCa.keyPair.private),
@ -186,7 +190,7 @@ class NodeRegistrationTest : IntegrationTest() {
private fun applyNetworkParametersAndStart(networkParametersCmd: NetworkParametersCmd) {
server?.close()
NetworkManagementServer(makeTestDataSourceProperties(dbName), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig).use {
NetworkManagementServer(makeTestDataSourceProperties(DOORMAN_DB_NAME, dbNamePostfix, fallBackConfigSupplier = ::networkMapInMemoryH2DataSourceConfig), makeTestDatabaseProperties(DOORMAN_DB_NAME), doormanConfig, revocationConfig).use {
it.processNetworkParameters(networkParametersCmd)
}
server = startServer(startNetworkMap = true)

View File

@ -35,7 +35,8 @@ class HsmKeyGenerationTest : HsmBaseTest() {
private lateinit var inputReader: InputReader
@Before
fun setUp() {
override fun setUp() {
super.setUp()
inputReader = mock()
whenever(inputReader.readLine()).thenReturn(hsmSimulator.cryptoUserCredentials().username)
whenever(inputReader.readPassword(any())).thenReturn(hsmSimulator.cryptoUserCredentials().password)

View File

@ -32,7 +32,6 @@ import net.corda.nodeapi.internal.crypto.X509Utilities.DEFAULT_TLS_SIGNATURE_SCH
import net.corda.nodeapi.internal.crypto.X509Utilities.createCertificateSigningRequest
import net.corda.nodeapi.internal.crypto.loadOrCreateKeyStore
import net.corda.nodeapi.internal.crypto.x509
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.common.internal.testNetworkParameters
import org.assertj.core.api.Assertions.assertThat
import org.junit.Before
@ -43,7 +42,8 @@ import kotlin.test.assertNotNull
class HsmSigningServiceTest : HsmBaseTest() {
@Before
fun setUp() {
override fun setUp() {
super.setUp()
loadOrCreateKeyStore(rootKeyStoreFile, TRUSTSTORE_PASSWORD)
}
@ -154,7 +154,7 @@ class HsmSigningServiceTest : HsmBaseTest() {
inputReader = userInput),
keyName = CORDA_NETWORK_MAP)
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true))
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties())
val networkMapStorage = PersistentNetworkMapStorage(database)
// given network map parameters

View File

@ -38,7 +38,6 @@ import net.corda.nodeapi.internal.createDevNodeCa
import net.corda.nodeapi.internal.crypto.CertificateAndKeyPair
import net.corda.nodeapi.internal.crypto.X509KeyStore
import net.corda.nodeapi.internal.crypto.X509Utilities
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.testing.core.ALICE_NAME
import net.corda.testing.core.SerializationEnvironmentRule
import net.corda.testing.internal.createDevIntermediateCaCertPath
@ -81,7 +80,8 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
@Before
fun setUp() {
override fun setUp() {
super.setUp()
dbName = random63BitValue().toString()
timer = Timer()
val (rootCa, intermediateCa) = createDevIntermediateCaCertPath()
@ -90,7 +90,8 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
}
@After
fun tearDown() {
override fun tearDown() {
super.tearDown()
timer.cancel()
}
@ -113,7 +114,7 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
@Test
fun `Signing service signs approved CSRs`() {
//Start doorman server
NetworkManagementServer(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true), doormanConfig, revocationConfig).use { server ->
NetworkManagementServer(makeTestDataSourceProperties(), makeTestDatabaseProperties(), doormanConfig, revocationConfig).use { server ->
server.start(
hostAndPort = NetworkHostAndPort(HOST, 0),
csrCertPathAndKey = null,
@ -124,7 +125,7 @@ class SigningServiceIntegrationTest : HsmBaseTest() {
doReturn(ALICE_NAME).whenever(it).myLegalName
doReturn(URL("http://${doormanHostAndPort.host}:${doormanHostAndPort.port}")).whenever(it).compatibilityZoneURL
}
val signingServiceStorage = DBSignedCertificateRequestStorage(configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(runMigration = true)))
val signingServiceStorage = DBSignedCertificateRequestStorage(configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties()))
val hsmSigner = givenSignerSigningAllRequests(signingServiceStorage)
// Poll the database for approved requests

View File

@ -12,6 +12,7 @@ package net.corda.node.services
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import com.typesafe.config.ConfigFactory
import net.corda.core.contracts.StateAndRef
import net.corda.core.contracts.StateRef
import net.corda.core.crypto.TransactionSignature
@ -34,11 +35,7 @@ import net.corda.testing.core.dummyCommand
import net.corda.testing.core.singleIdentity
import net.corda.testing.internal.IntegrationTest
import net.corda.testing.internal.IntegrationTestSchemas
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.inMemoryH2DataSourceConfig
import net.corda.testing.node.internal.InternalMockNetwork
import net.corda.testing.node.internal.InternalMockNodeParameters
import net.corda.testing.node.internal.startFlow
import net.corda.testing.node.internal.*
import org.junit.After
import org.junit.Before
import org.junit.ClassRule
@ -139,7 +136,7 @@ class MySQLNotaryServiceTests : IntegrationTest() {
}
private fun createNotaryNode(): InternalMockNetwork.MockNode {
val dataStoreProperties = makeTestDataSourceProperties(configSupplier = ::inMemoryH2DataSourceConfig).apply {
val dataStoreProperties = makeTestDataSourceProperties(configSupplier = { _, _ ->ConfigFactory.empty() }, fallBackConfigSupplier = ::inMemoryH2DataSourceConfig).apply {
setProperty("autoCommit", "false")
}
return mockNet.createUnstartedNode(

View File

@ -37,9 +37,6 @@ import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.api.SchemaService
import net.corda.node.services.api.VaultServiceInternal
import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.configOf
import net.corda.node.services.config.parseToDbSchemaFriendlyName
import net.corda.node.services.api.*
import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.node.services.schema.HibernateObserver
@ -50,16 +47,9 @@ import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.HibernateConfiguration
import net.corda.testing.common.internal.testNetworkParameters
import net.corda.testing.core.TestIdentity
import net.corda.testing.database.DatabaseConstants
import net.corda.testing.database.DatabaseConstants.DATA_SOURCE_CLASSNAME
import net.corda.testing.database.DatabaseConstants.DATA_SOURCE_PASSWORD
import net.corda.testing.database.DatabaseConstants.DATA_SOURCE_URL
import net.corda.testing.database.DatabaseConstants.DATA_SOURCE_USER
import net.corda.testing.internal.DEV_ROOT_CA
import net.corda.testing.internal.MockCordappProvider
import net.corda.testing.node.internal.MockKeyManagementService
import net.corda.testing.node.internal.MockTransactionStorage
import net.corda.testing.node.internal.makeTestDatabaseProperties
import net.corda.testing.node.internal.*
import net.corda.testing.services.MockAttachmentStorage
import java.security.KeyPair
import java.sql.Connection
@ -91,25 +81,25 @@ open class MockServices private constructor(
companion object {
/**
* Make properties appropriate for creating a DataSource for unit tests.
* Defaults configuration of in-memory H2 instance. If 'databaseProvider' system property is set then creates
* a config from the relevant config file is present in resources folder (used to parametrize test to run against a remote database).
*
* @param nodeName Reflects the "instance" of the in-memory database or database username/schema. Defaults to a random string.
* @param nodeNameExtension Provides additional name extension for the "instance" of in-memory database to provide uniqueness when running unit tests against H2 db.
* @param configSupplier returns [Config] with dataSourceProperties entry.
* @param nodeName Reflects the "instance" of the in-memory database or database username/schema.
* Defaults to a random string. Passed to [configSupplier] method.
* @param nodeNameExtension Provides additional name extension for [configSupplier].
* @param configSupplier Returns [Config] with dataSourceProperties, invoked with [nodeName] and [nodeNameExtension] parameters.
* Defaults to configuration created when 'databaseProvider' system property is set.
*/
// TODO: Can we use an X509 principal generator here?
@JvmStatic
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString(), nodeNameExtension: String? = null,
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString(),
nodeNameExtension: String? = null,
configSupplier: (String, String?) -> Config = ::databaseProviderDataSourceConfig): Properties {
val config = configSupplier(nodeName, nodeNameExtension)
val props = Properties()
props.setProperty("dataSourceClassName", config.getString("dataSourceProperties.dataSourceClassName"))
props.setProperty("dataSource.url", config.getString("dataSourceProperties.dataSource.url"))
props.setProperty("dataSource.user", config.getString("dataSourceProperties.dataSource.user"))
props.setProperty("dataSource.password", config.getString("dataSourceProperties.dataSource.password"))
props["autoCommit"] = false
return props
return makeTestDataSourceProperties(nodeName, nodeNameExtension, configSupplier, ::inMemoryH2DataSourceConfig)
}
/**
* Makes database and mock services appropriate for unit tests.
*
@ -318,54 +308,4 @@ fun <T : SerializeAsToken> createMockCordaService(serviceHub: MockServices, serv
}
}
return MockAppServiceHubImpl(serviceHub, serviceConstructor).serviceInstance
}
/**
* Reads database and dataSource configuration from a file denoted by 'databaseProvider' system property,
* overwitten by system properties and defaults to H2 in memory db.
* @param nodeName Reflects the "instance" of the database username/schema, the value will be used to replace ${custom.nodeOrganizationName} placeholder
* if the placeholder is present in config.
* @param postfix Additional postix added to database "instance" name in case config defaults to H2 in memory database.
*/
fun databaseProviderDataSourceConfig(nodeName: String? = null, postfix: String? = null): Config {
val parseOptions = ConfigParseOptions.defaults()
//read overrides from command line (passed by Gradle as system properties)
val systemConfigOverride = ConfigFactory.parseMap(System.getProperties().filterKeys { (it as String).startsWith(ConfigHelper.CORDA_PROPERTY_PREFIX) }
.mapKeys { (it.key as String).removePrefix(ConfigHelper.CORDA_PROPERTY_PREFIX) }
.filterKeys { listOf(DATA_SOURCE_URL, DATA_SOURCE_CLASSNAME, DATA_SOURCE_USER, DATA_SOURCE_PASSWORD).contains(it) })
//read from db vendor specific configuration file
val databaseConfig = ConfigFactory.parseResources(System.getProperty("custom.databaseProvider") + ".conf", parseOptions.setAllowMissing(true))
val fixedOverride = ConfigFactory.parseString("baseDirectory = \"\"")
//implied property custom.nodeOrganizationName to fill the potential placeholders in db schema/ db user properties
val nodeOrganizationNameConfig = if (nodeName != null) configOf("custom.nodeOrganizationName" to parseToDbSchemaFriendlyName(nodeName)) else ConfigFactory.empty()
//defaults to H2
//for H2 the same db instance runs for all integration tests, so adding additional variable postfix create a unique database each time
val defaultConfig = inMemoryH2DataSourceConfig(nodeName, postfix)
return systemConfigOverride.withFallback(databaseConfig)
.withFallback(fixedOverride)
.withFallback(nodeOrganizationNameConfig)
.withFallback(defaultConfig)
.resolve()
}
/**
* Creates data source configuration for in memory H2 as it would be specified in reference.conf 'datasource' snippet.
* @param nodeName Reflects the "instance" of the database username/schema
* @param postfix Additional postix added to database "instance" name to add uniqueness when running integration tests.
*/
fun inMemoryH2DataSourceConfig(nodeName: String? = null, postfix: String? = null) : Config {
val nodeName = nodeName ?: SecureHash.randomSHA256().toString()
val h2InstanceName = if (postfix != null) nodeName + "_" + postfix else nodeName
return ConfigFactory.parseMap(mapOf(
DatabaseConstants.DATA_SOURCE_CLASSNAME to "org.h2.jdbcx.JdbcDataSource",
DatabaseConstants.DATA_SOURCE_URL to "jdbc:h2:mem:${h2InstanceName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE",
DatabaseConstants.DATA_SOURCE_USER to "sa",
DatabaseConstants.DATA_SOURCE_PASSWORD to ""))
}

View File

@ -10,10 +10,14 @@
package net.corda.testing.node.internal
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigParseOptions
import net.corda.client.rpc.CordaRPCClient
import net.corda.core.CordaException
import net.corda.core.concurrent.CordaFuture
import net.corda.core.context.InvocationContext
import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.internal.FlowStateMachine
import net.corda.core.internal.concurrent.openFuture
@ -23,6 +27,9 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.millis
import net.corda.core.utilities.seconds
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.ConfigHelper
import net.corda.node.services.config.configOf
import net.corda.node.services.config.parseToDbSchemaFriendlyName
import net.corda.node.services.messaging.Message
import net.corda.node.services.messaging.MessagingService
import net.corda.nodeapi.internal.persistence.DatabaseConfig
@ -31,12 +38,12 @@ import net.corda.testing.database.DatabaseConstants
import net.corda.testing.internal.chooseIdentity
import net.corda.testing.node.InMemoryMessagingNetwork
import net.corda.testing.node.User
import net.corda.testing.node.databaseProviderDataSourceConfig
import net.corda.testing.node.testContext
import org.slf4j.LoggerFactory
import java.net.Socket
import java.net.SocketException
import java.time.Duration
import java.util.*
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
@ -129,6 +136,38 @@ internal interface InternalMockMessagingService : MessagingService {
fun stop()
}
/**
* Make properties appropriate for creating a DataSource for unit tests.
* Defaults configuration of in-memory H2 instance. If 'databaseProvider' system property is set then creates
* a config from the relevant config file is present in resources folder (used to parametrize test to run against a remote database).
* Properties retrieval can be parameterized by [configSupplier] and/or [fallBackConfigSupplier] methods
* which are run with [nodeName] and [nodeNameExtension] parameters.
*
* @param nodeName Reflects the "instance" of the in-memory database or database username/schema.
* Defaults to a random string. Passed to [configSupplier] and [fallBackConfigSupplier] methods.
* @param nodeNameExtension Provides additional name extension for [configSupplier] and [fallBackConfigSupplier].
* @param configSupplier Returns [Config] with dataSourceProperties, invoked with [nodeName] and [nodeNameExtension] parameters.
* Defaults to configuration created when 'databaseProvider' system property is set.
* @param fallBackConfigSupplier Returns [Config] with dataSourceProperties, invoked with [nodeName] and [nodeNameExtension] parameters.
* Defaults to configuration of in-memory H2 instance.
*/
fun makeTestDataSourceProperties(nodeName: String = SecureHash.randomSHA256().toString(),
nodeNameExtension: String? = null,
configSupplier: (String, String?) -> Config = ::databaseProviderDataSourceConfig,
fallBackConfigSupplier: (String?, String?) -> Config = ::inMemoryH2DataSourceConfig): Properties {
val config = configSupplier(nodeName, nodeNameExtension)
.withFallback(fallBackConfigSupplier(nodeName, nodeNameExtension))
.resolve()
val props = Properties()
props.setProperty("dataSourceClassName", config.getString("dataSourceProperties.dataSourceClassName"))
props.setProperty("dataSource.url", config.getString("dataSourceProperties.dataSource.url"))
props.setProperty("dataSource.user", config.getString("dataSourceProperties.dataSource.user"))
props.setProperty("dataSource.password", config.getString("dataSourceProperties.dataSource.password"))
props.setProperty("autoCommit", "false")
return props
}
/**
* Make properties appropriate for creating a Database for unit tests.
*
@ -136,10 +175,59 @@ internal interface InternalMockMessagingService : MessagingService {
*/
fun makeTestDatabaseProperties(nodeName: String? = null): DatabaseConfig {
val config = databaseProviderDataSourceConfig(nodeName)
val transactionIsolationLevel = if (config.hasPath(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL)) TransactionIsolationLevel.valueOf(config.getString(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL))
val transactionIsolationLevel = if (config.hasPath(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL))
TransactionIsolationLevel.valueOf(config.getString(DatabaseConstants.TRANSACTION_ISOLATION_LEVEL))
else TransactionIsolationLevel.READ_COMMITTED
val schema = if (config.hasPath(DatabaseConstants.SCHEMA)) config.getString(DatabaseConstants.SCHEMA) else ""
return DatabaseConfig(runMigration = true, transactionIsolationLevel = transactionIsolationLevel, schema = schema)
}
/**
* Reads database and dataSource configuration from a file denoted by 'databaseProvider' system property,
* overwritten by system properties and defaults to H2 in memory db.
* @param nodeName Reflects the "instance" of the database username/schema, the value will be used to replace ${custom.nodeOrganizationName} placeholder
* @param notUsed Not uses, required for API backward compatibility.
* if the placeholder is present in config.
*/
fun databaseProviderDataSourceConfig(nodeName: String? = null, notUsed: String? = null): Config {
val parseOptions = ConfigParseOptions.defaults()
val keys = listOf(DatabaseConstants.DATA_SOURCE_URL, DatabaseConstants.DATA_SOURCE_CLASSNAME,
DatabaseConstants.DATA_SOURCE_USER, DatabaseConstants.DATA_SOURCE_PASSWORD)
//read overrides from command line (passed by Gradle as system properties)
val systemConfigOverride = ConfigFactory.parseMap(System.getProperties()
.filterKeys { (it as String).startsWith(ConfigHelper.CORDA_PROPERTY_PREFIX) }
.mapKeys { (it.key as String).removePrefix(ConfigHelper.CORDA_PROPERTY_PREFIX) }
.filterKeys { it in keys })
//read from db vendor specific configuration file
val databaseConfig = ConfigFactory.parseResources(System.getProperty("custom.databaseProvider") + ".conf", parseOptions.setAllowMissing(true))
val fixedOverride = ConfigFactory.parseString("baseDirectory = \"\"")
//implied property custom.nodeOrganizationName to fill the potential placeholders in db schema/ db user properties
val nodeOrganizationNameConfig = if (nodeName != null) configOf("custom.nodeOrganizationName" to parseToDbSchemaFriendlyName(nodeName)) else ConfigFactory.empty()
return systemConfigOverride.withFallback(databaseConfig)
.withFallback(fixedOverride)
.withFallback(nodeOrganizationNameConfig)
.resolve()
}
/**
* Creates data source configuration for in memory H2 as it would be specified in reference.conf 'datasource' snippet.
* @param nodeName Reflects the "instance" of the database username/schema
* @param postfix Additional postix added to database "instance" name to add uniqueness when running integration tests.
*/
fun inMemoryH2DataSourceConfig(nodeName: String? = null, postfix: String? = null) : Config {
val nodeName = nodeName ?: SecureHash.randomSHA256().toString()
val h2InstanceName = if (postfix != null) nodeName + "_" + postfix else nodeName
return ConfigFactory.parseMap(mapOf(
DatabaseConstants.DATA_SOURCE_CLASSNAME to "org.h2.jdbcx.JdbcDataSource",
DatabaseConstants.DATA_SOURCE_URL to "jdbc:h2:mem:${h2InstanceName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE",
DatabaseConstants.DATA_SOURCE_USER to "sa",
DatabaseConstants.DATA_SOURCE_PASSWORD to ""))
}
fun CordaRPCClient.start(user: User) = start(user.username, user.password)

View File

@ -51,6 +51,19 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request_AUD;
DROP TABLE IF EXISTS ${schema}.cert_signing_request_AUD;
DROP TABLE IF EXISTS ${schema}.network_map_AUD;
DROP TABLE IF EXISTS ${schema}.REVINFO;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request;
DROP TABLE IF EXISTS ${schema}.cert_data;
DROP TABLE IF EXISTS ${schema}.cert_revocation_list;
DROP TABLE IF EXISTS ${schema}.node_info;
DROP TABLE IF EXISTS ${schema}.cert_signing_request;
DROP TABLE IF EXISTS ${schema}.network_map;
DROP TABLE IF EXISTS ${schema}.parameters_update;
DROP TABLE IF EXISTS ${schema}.network_parameters;
DROP TABLE IF EXISTS ${schema}.private_network;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
DROP USER IF EXISTS ${schema};
DROP SCHEMA IF EXISTS ${schema};

View File

@ -51,4 +51,17 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request_AUD;
DROP TABLE IF EXISTS ${schema}.cert_signing_request_AUD;
DROP TABLE IF EXISTS ${schema}.network_map_AUD;
DROP TABLE IF EXISTS ${schema}.REVINFO;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request;
DROP TABLE IF EXISTS ${schema}.cert_data;
DROP TABLE IF EXISTS ${schema}.cert_revocation_list;
DROP TABLE IF EXISTS ${schema}.node_info;
DROP TABLE IF EXISTS ${schema}.cert_signing_request;
DROP TABLE IF EXISTS ${schema}.network_map;
DROP TABLE IF EXISTS ${schema}.parameters_update;
DROP TABLE IF EXISTS ${schema}.network_parameters;
DROP TABLE IF EXISTS ${schema}.private_network;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;

View File

@ -30,4 +30,5 @@ CREATE LOGIN RAFTNotaryService_0 WITH PASSWORD = 'yourStrong(!)Password';
CREATE LOGIN RAFTNotaryService_1 WITH PASSWORD = 'yourStrong(!)Password';
CREATE LOGIN RAFTNotaryService_2 WITH PASSWORD = 'yourStrong(!)Password';
CREATE LOGIN Regulator WITH PASSWORD = 'yourStrong(!)Password';
CREATE LOGIN RegulatorA WITH PASSWORD = 'yourStrong(!)Password';
CREATE LOGIN RegulatorA WITH PASSWORD = 'yourStrong(!)Password';
CREATE LOGIN doorman WITH PASSWORD = 'yourStrong(!)Password';

View File

@ -51,4 +51,17 @@ DROP TABLE ${schema}.dummy_linear_states_v2 CASCADE CONSTRAINTS
DROP TABLE ${schema}.node_mutual_exclusion CASCADE CONSTRAINTS
DROP TABLE ${schema}.DATABASECHANGELOG CASCADE CONSTRAINTS
DROP TABLE ${schema}.DATABASECHANGELOGLOCK CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_revocation_request_AUD CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_signing_request_AUD CASCADE CONSTRAINTS
DROP TABLE ${schema}.network_map_AUD CASCADE CONSTRAINTS
DROP TABLE ${schema}.REVINFO CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_revocation_request CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_data CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_revocation_list CASCADE CONSTRAINTS
DROP TABLE ${schema}.node_info CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_signing_request CASCADE CONSTRAINTS
DROP TABLE ${schema}.network_map CASCADE CONSTRAINTS
DROP TABLE ${schema}.parameters_update CASCADE CONSTRAINTS
DROP TABLE ${schema}.network_parameters CASCADE CONSTRAINTS
DROP TABLE ${schema}.private_network CASCADE CONSTRAINTS
DROP SEQUENCE ${schema}.hibernate_sequence

View File

@ -51,4 +51,17 @@ DROP TABLE ${schema}.dummy_linear_states_v2 CASCADE CONSTRAINTS
DROP TABLE ${schema}.node_mutual_exclusion CASCADE CONSTRAINTS
DROP TABLE ${schema}.DATABASECHANGELOG CASCADE CONSTRAINTS
DROP TABLE ${schema}.DATABASECHANGELOGLOCK CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_revocation_request_AUD CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_signing_request_AUD CASCADE CONSTRAINTS
DROP TABLE ${schema}.network_map_AUD CASCADE CONSTRAINTS
DROP TABLE ${schema}.REVINFO CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_revocation_request CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_data CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_revocation_list CASCADE CONSTRAINTS
DROP TABLE ${schema}.node_info CASCADE CONSTRAINTS
DROP TABLE ${schema}.cert_signing_request CASCADE CONSTRAINTS
DROP TABLE ${schema}.network_map CASCADE CONSTRAINTS
DROP TABLE ${schema}.parameters_update CASCADE CONSTRAINTS
DROP TABLE ${schema}.network_parameters CASCADE CONSTRAINTS
DROP TABLE ${schema}.private_network CASCADE CONSTRAINTS
DROP SEQUENCE ${schema}.hibernate_sequence

View File

@ -51,6 +51,19 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request_AUD;
DROP TABLE IF EXISTS ${schema}.cert_signing_request_AUD;
DROP TABLE IF EXISTS ${schema}.network_map_AUD;
DROP TABLE IF EXISTS ${schema}.REVINFO;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request;
DROP TABLE IF EXISTS ${schema}.cert_data;
DROP TABLE IF EXISTS ${schema}.cert_revocation_list;
DROP TABLE IF EXISTS ${schema}.node_info;
DROP TABLE IF EXISTS ${schema}.cert_signing_request;
DROP TABLE IF EXISTS ${schema}.network_map;
DROP TABLE IF EXISTS ${schema}.parameters_update;
DROP TABLE IF EXISTS ${schema}.network_parameters;
DROP TABLE IF EXISTS ${schema}.private_network;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
DROP USER IF EXISTS ${schema};
DROP LOGIN ${schema};

View File

@ -50,6 +50,19 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request_AUD;
DROP TABLE IF EXISTS ${schema}.cert_signing_request_AUD;
DROP TABLE IF EXISTS ${schema}.network_map_AUD;
DROP TABLE IF EXISTS ${schema}.REVINFO;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request;
DROP TABLE IF EXISTS ${schema}.cert_data;
DROP TABLE IF EXISTS ${schema}.cert_revocation_list;
DROP TABLE IF EXISTS ${schema}.node_info;
DROP TABLE IF EXISTS ${schema}.cert_signing_request;
DROP TABLE IF EXISTS ${schema}.network_map;
DROP TABLE IF EXISTS ${schema}.parameters_update;
DROP TABLE IF EXISTS ${schema}.network_parameters;
DROP TABLE IF EXISTS ${schema}.private_network;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
DROP USER IF EXISTS ${schema};
DROP LOGIN ${schema};

View File

@ -51,6 +51,19 @@ DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
DROP TABLE IF EXISTS ${schema}.node_mutual_exclusion;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOG;
DROP TABLE IF EXISTS ${schema}.DATABASECHANGELOGLOCK;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request_AUD;
DROP TABLE IF EXISTS ${schema}.cert_signing_request_AUD;
DROP TABLE IF EXISTS ${schema}.network_map_AUD;
DROP TABLE IF EXISTS ${schema}.REVINFO;
DROP TABLE IF EXISTS ${schema}.cert_revocation_request;
DROP TABLE IF EXISTS ${schema}.cert_data;
DROP TABLE IF EXISTS ${schema}.cert_revocation_list;
DROP TABLE IF EXISTS ${schema}.node_info;
DROP TABLE IF EXISTS ${schema}.cert_signing_request;
DROP TABLE IF EXISTS ${schema}.network_map;
DROP TABLE IF EXISTS ${schema}.parameters_update;
DROP TABLE IF EXISTS ${schema}.network_parameters;
DROP TABLE IF EXISTS ${schema}.private_network;
DROP SEQUENCE IF EXISTS ${schema}.hibernate_sequence;
IF NOT EXISTS (SELECT schema_name FROM information_schema.schemata WHERE schema_name = '${schema}') EXEC('CREATE SCHEMA ${schema}');
IF NOT EXISTS (SELECT * FROM sys.sysusers WHERE name='${schema}') CREATE USER ${schema} FOR LOGIN ${schema} WITH DEFAULT_SCHEMA = ${schema};