Made the database config option typesafe, rather than relying on String properties

This commit is contained in:
Shams Asari 2017-11-25 15:55:31 +00:00
parent c4b333c50c
commit 1705df4d1f
26 changed files with 155 additions and 139 deletions

4
.idea/compiler.xml generated
View File

@ -43,8 +43,6 @@
<module name="docs_source_example-code_main" target="1.8" />
<module name="docs_source_example-code_test" target="1.8" />
<module name="docs_test" target="1.8" />
<module name="experimental-kryo-hook_main" target="1.8" />
<module name="experimental-kryo-hook_test" target="1.8" />
<module name="example-code_integrationTest" target="1.8" />
<module name="example-code_main" target="1.8" />
<module name="example-code_test" target="1.8" />
@ -59,6 +57,8 @@
<module name="finance_integrationTest" target="1.8" />
<module name="finance_main" target="1.8" />
<module name="finance_test" target="1.8" />
<module name="gradle-plugins-cordapp_main" target="1.8" />
<module name="gradle-plugins-cordapp_test" target="1.8" />
<module name="graphs_main" target="1.8" />
<module name="graphs_test" target="1.8" />
<module name="irs-demo-cordapp_integrationTest" target="1.8" />

View File

@ -304,6 +304,6 @@ fun TransactionBuilder.toWireTransaction(services: ServicesForResolution, serial
fun TransactionBuilder.toLedgerTransaction(services: ServiceHub, serializationContext: SerializationContext) = toLedgerTransactionWithContext(services, serializationContext)
/** Convenience method to get the package name of a class literal. */
val KClass<*>.packageName get() = java.`package`.name
val KClass<*>.packageName: String get() = java.`package`.name
fun URL.openHttpConnection(): HttpURLConnection = openConnection() as HttpURLConnection

View File

@ -91,6 +91,9 @@ UNRELEASED
* ``waitForAllNodesToFinish()`` method in ``DriverDSLExposedInterface`` has instead become a parameter on driver creation.
* ``database.transactionIsolationLevel`` values now follow the ``java.sql.Connection`` int constants but without the
"TRANSACTION_" prefix, i.e. "NONE", "READ_UNCOMMITTED", etc.
.. _changelog_v1:
Release 1.0

View File

@ -68,6 +68,13 @@ path to the node's base directory.
.. note:: Longer term these keys will be managed in secure hardware devices.
:database: Database configuration:
:initDatabase: Boolean on whether to initialise the database or just validate the schema. Defaults to true.
:serverNameTablePrefix: Prefix string to apply to all the database tables. The default is no prefix.
:transactionIsolationLevel: Transaction isolation level as defined by the ``TRANSACTION_`` constants in
``java.sql.Connection``, but without the "TRANSACTION_" prefix. Defaults to REPEATABLE_READ.
:dataSourceProperties: This section is used to configure the jdbc connection and database driver used for the nodes persistence.
Currently the defaults in ``/node/src/main/resources/reference.conf`` are as shown in the first example. This is currently
the only configuration that has been tested, although in the future full support for other storage layers will be validated.

View File

@ -131,7 +131,13 @@ private fun Config.defaultToOldPath(property: KProperty<*>): String {
private fun parseEnum(enumType: Class<*>, name: String): Enum<*> = enumBridge<Proxy.Type>(uncheckedCast(enumType), name) // Any enum will do
private fun <T : Enum<T>> enumBridge(clazz: Class<T>, name: String): T = java.lang.Enum.valueOf(clazz, name)
private fun <T : Enum<T>> enumBridge(clazz: Class<T>, name: String): T {
try {
return java.lang.Enum.valueOf(clazz, name)
} catch (e: IllegalArgumentException) {
throw IllegalArgumentException("$name is not one of { ${clazz.enumConstants.joinToString()} }")
}
}
/**
* Convert the receiver object into a [Config]. This does the inverse action of [parseAs].

View File

@ -8,6 +8,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.div
import net.corda.core.utilities.NetworkHostAndPort
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test
import java.net.URL
import java.nio.file.Path
@ -47,6 +48,14 @@ class ConfigParsingTest {
testPropertyType<EnumData, EnumListData, TestEnum>(TestEnum.Value2, TestEnum.Value1, valuesToString = true)
}
@Test
fun `unknown Enum`() {
val config = config("value" to "UnknownValue")
assertThatThrownBy { config.parseAs<EnumData>() }
.hasMessageContaining(TestEnum.Value1.name)
.hasMessageContaining(TestEnum.Value2.name)
}
@Test
fun `LocalDate`() {
testPropertyType<LocalDateData, LocalDateListData, LocalDate>(LocalDate.now(), LocalDate.now().plusDays(1), valuesToString = true)

View File

@ -12,8 +12,6 @@ import java.net.URL
import java.nio.file.Path
import java.util.*
data class DevModeOptions(val disableCheckpointChecker: Boolean = false)
interface NodeConfiguration : NodeSSLConfiguration {
// myLegalName should be only used in the initial network registration, we should use the name from the certificate instead of this.
// TODO: Remove this so we don't accidentally use this identity in the code?
@ -21,7 +19,7 @@ interface NodeConfiguration : NodeSSLConfiguration {
val emailAddress: String
val exportJMXto: String
val dataSourceProperties: Properties
val database: Properties?
val database: DatabaseConfig
val rpcUsers: List<User>
val devMode: Boolean
val devModeOptions: DevModeOptions?
@ -42,6 +40,27 @@ interface NodeConfiguration : NodeSSLConfiguration {
val sshd: SSHDConfiguration?
}
data class DevModeOptions(val disableCheckpointChecker: Boolean = false)
data class DatabaseConfig(
val initDatabase: Boolean = true,
val serverNameTablePrefix: String = "",
val transactionIsolationLevel: TransactionIsolationLevel = TransactionIsolationLevel.REPEATABLE_READ
)
enum class TransactionIsolationLevel {
NONE,
READ_UNCOMMITTED,
READ_COMMITTED,
REPEATABLE_READ,
SERIALIZABLE;
/**
* The JDBC constant value of the same name but with prefixed with TRANSACTION_ defined in [java.sql.Connection].
*/
val jdbcValue: Int = java.sql.Connection::class.java.getField("TRANSACTION_$name").get(null) as Int
}
fun NodeConfiguration.shouldCheckCheckpoints(): Boolean {
return this.devMode && this.devModeOptions?.disableCheckpointChecker != true
}
@ -89,7 +108,7 @@ data class NodeConfigurationImpl(
override val keyStorePassword: String,
override val trustStorePassword: String,
override val dataSourceProperties: Properties,
override val database: Properties?,
override val database: DatabaseConfig = DatabaseConfig(),
override val compatibilityZoneURL: URL? = null,
override val rpcUsers: List<User>,
override val verifierType: VerifierType,

View File

@ -6,8 +6,8 @@ import net.corda.core.schemas.MappedSchema
import net.corda.core.utilities.contextLogger
import net.corda.core.utilities.toHexString
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.utilities.DatabaseTransactionManager
import net.corda.node.utilities.parserTransactionIsolationLevel
import org.hibernate.SessionFactory
import org.hibernate.boot.MetadataSources
import org.hibernate.boot.model.naming.Identifier
@ -23,10 +23,9 @@ import org.hibernate.type.descriptor.java.PrimitiveByteArrayTypeDescriptor
import org.hibernate.type.descriptor.sql.BlobTypeDescriptor
import org.hibernate.type.descriptor.sql.VarbinaryTypeDescriptor
import java.sql.Connection
import java.util.*
import java.util.concurrent.ConcurrentHashMap
class HibernateConfiguration(val schemaService: SchemaService, private val databaseProperties: Properties, private val identityService: IdentityService) {
class HibernateConfiguration(val schemaService: SchemaService, private val databaseConfig: DatabaseConfig, private val identityService: IdentityService) {
companion object {
private val logger = contextLogger()
}
@ -34,7 +33,6 @@ class HibernateConfiguration(val schemaService: SchemaService, private val datab
// TODO: make this a guava cache or similar to limit ability for this to grow forever.
private val sessionFactories = ConcurrentHashMap<Set<MappedSchema>, SessionFactory>()
private val transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel") ?: "")
val sessionFactoryForRegisteredSchemas = schemaService.schemaOptions.keys.let {
logger.info("Init HibernateConfiguration for schemas: $it")
// Register the AbstractPartyDescriptor so Hibernate doesn't warn when encountering AbstractParty. Unfortunately
@ -56,16 +54,16 @@ class HibernateConfiguration(val schemaService: SchemaService, private val datab
// necessarily remain and would likely be replaced by something like Liquibase. For now it is very convenient though.
// TODO: replace auto schema generation as it isn't intended for production use, according to Hibernate docs.
val config = Configuration(metadataSources).setProperty("hibernate.connection.provider_class", NodeDatabaseConnectionProvider::class.java.name)
.setProperty("hibernate.hbm2ddl.auto", if (databaseProperties.getProperty("initDatabase", "true") == "true") "update" else "validate")
.setProperty("hibernate.hbm2ddl.auto", if (databaseConfig.initDatabase) "update" else "validate")
.setProperty("hibernate.format_sql", "true")
.setProperty("hibernate.connection.isolation", transactionIsolationLevel.toString())
.setProperty("hibernate.connection.isolation", databaseConfig.transactionIsolationLevel.jdbcValue.toString())
schemas.forEach { schema ->
// TODO: require mechanism to set schemaOptions (databaseSchema, tablePrefix) which are not global to session
schema.mappedTypes.forEach { config.addAnnotatedClass(it) }
}
val sessionFactory = buildSessionFactory(config, metadataSources, databaseProperties.getProperty("serverNameTablePrefix", ""))
val sessionFactory = buildSessionFactory(config, metadataSources, databaseConfig.serverNameTablePrefix)
logger.info("Created session factory for schemas: $schemas")
return sessionFactory
}
@ -132,11 +130,13 @@ class HibernateConfiguration(val schemaService: SchemaService, private val datab
private val LOG_SIZE_LIMIT = 1024
override fun extractLoggableRepresentation(value: ByteArray?): String {
return if (value == null) super.extractLoggableRepresentation(value) else {
return if (value == null) {
super.extractLoggableRepresentation(value)
} else {
if (value.size <= LOG_SIZE_LIMIT) {
return "[size=${value.size}, value=${value.toHexString()}]"
"[size=${value.size}, value=${value.toHexString()}]"
} else {
return "[size=${value.size}, value=${value.copyOfRange(0, LOG_SIZE_LIMIT).toHexString()}...truncated...]"
"[size=${value.size}, value=${value.copyOfRange(0, LOG_SIZE_LIMIT).toHexString()}...truncated...]"
}
}
}

View File

@ -4,6 +4,7 @@ import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import net.corda.core.node.services.IdentityService
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.persistence.HibernateConfiguration
import net.corda.node.services.schema.NodeSchemaService
import rx.Observable
@ -21,20 +22,23 @@ import java.util.concurrent.CopyOnWriteArrayList
const val NODE_DATABASE_PREFIX = "node_"
//HikariDataSource implements Closeable which allows CordaPersistence to be Closeable
class CordaPersistence(var dataSource: HikariDataSource, private val schemaService: SchemaService,
private val identityService: IdentityService, databaseProperties: Properties) : Closeable {
var transactionIsolationLevel = parserTransactionIsolationLevel(databaseProperties.getProperty("transactionIsolationLevel"))
class CordaPersistence(
val dataSource: HikariDataSource,
private val schemaService: SchemaService,
private val identityService: IdentityService,
databaseConfig: DatabaseConfig
) : Closeable {
val transactionIsolationLevel = databaseConfig.transactionIsolationLevel.jdbcValue
val hibernateConfig: HibernateConfiguration by lazy {
transaction {
HibernateConfiguration(schemaService, databaseProperties, identityService)
HibernateConfiguration(schemaService, databaseConfig, identityService)
}
}
val entityManagerFactory get() = hibernateConfig.sessionFactoryForRegisteredSchemas
companion object {
fun connect(dataSource: HikariDataSource, schemaService: SchemaService, identityService: IdentityService, databaseProperties: Properties): CordaPersistence {
return CordaPersistence(dataSource, schemaService, identityService, databaseProperties).apply {
fun connect(dataSource: HikariDataSource, schemaService: SchemaService, identityService: IdentityService, databaseConfig: DatabaseConfig): CordaPersistence {
return CordaPersistence(dataSource, schemaService, identityService, databaseConfig).apply {
DatabaseTransactionManager(this)
}
}
@ -53,9 +57,7 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi
/**
* Creates an instance of [DatabaseTransaction], with the transaction isolation level specified at the creation time.
*/
fun createTransaction(): DatabaseTransaction {
return createTransaction(transactionIsolationLevel)
}
fun createTransaction(): DatabaseTransaction = createTransaction(transactionIsolationLevel)
fun createSession(): Connection {
// We need to set the database for the current [Thread] or [Fiber] here as some tests share threads across databases.
@ -78,9 +80,7 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi
* Executes given statement in the scope of transaction with the transaction level specified at the creation time.
* @param statement to be executed in the scope of this transaction.
*/
fun <T> transaction(statement: DatabaseTransaction.() -> T): T {
return transaction(transactionIsolationLevel, statement)
}
fun <T> transaction(statement: DatabaseTransaction.() -> T): T = transaction(transactionIsolationLevel, statement)
private fun <T> transaction(transactionIsolation: Int, repetitionAttempts: Int, statement: DatabaseTransaction.() -> T): T {
val outer = DatabaseTransactionManager.currentOrNull()
@ -120,10 +120,10 @@ class CordaPersistence(var dataSource: HikariDataSource, private val schemaServi
}
}
fun configureDatabase(dataSourceProperties: Properties, databaseProperties: Properties?, identityService: IdentityService, schemaService: SchemaService = NodeSchemaService(null)): CordaPersistence {
fun configureDatabase(dataSourceProperties: Properties, databaseConfig: DatabaseConfig, identityService: IdentityService, schemaService: SchemaService = NodeSchemaService(null)): CordaPersistence {
val config = HikariConfig(dataSourceProperties)
val dataSource = HikariDataSource(config)
val persistence = CordaPersistence.connect(dataSource, schemaService, identityService, databaseProperties ?: Properties())
val persistence = CordaPersistence.connect(dataSource, schemaService, identityService, databaseConfig)
// Check not in read-only mode.
persistence.transaction {
persistence.dataSource.connection.use {
@ -216,15 +216,3 @@ fun <T : Any> rx.Observable<T>.wrapWithDatabaseTransaction(db: CordaPersistence?
}
}
}
fun parserTransactionIsolationLevel(property: String?): Int =
when (property) {
"none" -> Connection.TRANSACTION_NONE
"readUncommitted" -> Connection.TRANSACTION_READ_UNCOMMITTED
"readCommitted" -> Connection.TRANSACTION_READ_COMMITTED
"repeatableRead" -> Connection.TRANSACTION_REPEATABLE_READ
"serializable" -> Connection.TRANSACTION_SERIALIZABLE
else -> {
Connection.TRANSACTION_REPEATABLE_READ
}
}

View File

@ -10,7 +10,7 @@ dataSourceProperties = {
"dataSource.password" = ""
}
database = {
transactionIsolationLevel = "repeatableRead"
transactionIsolationLevel = "REPEATABLE_READ"
initDatabase = true
}
devMode = true

View File

@ -7,10 +7,10 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.flows.FlowLogic
import net.corda.core.flows.StateMachineRunId
import net.corda.core.identity.Party
import net.corda.core.internal.FlowStateMachine
import net.corda.core.internal.concurrent.openFuture
import net.corda.core.messaging.FlowProgressHandleImpl
import net.corda.core.utilities.ProgressTracker
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.node.shell.InteractiveShell
import net.corda.node.utilities.configureDatabase
@ -29,7 +29,7 @@ import kotlin.test.assertEquals
class InteractiveShellTest {
@Before
fun setup() {
InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), MockServices.makeTestDatabaseProperties(), rigorousMock())
InteractiveShell.database = configureDatabase(MockServices.makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock())
}
@After
@ -92,6 +92,4 @@ class InteractiveShellTest {
@Test
fun party() = check("party: \"${MEGA_CORP.name}\"", MEGA_CORP.name.toString())
class DummyFSM(override val logic: FlowA) : FlowStateMachine<Any?> by rigorousMock()
}

View File

@ -3,10 +3,8 @@ package net.corda.node.services.config
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.testing.ALICE
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.Test
import java.net.URL
import java.nio.file.Paths
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@ -40,7 +38,7 @@ class NodeConfigurationImplTest {
keyStorePassword = "cordacadevpass",
trustStorePassword = "trustpass",
dataSourceProperties = makeTestDataSourceProperties(ALICE.name.organisation),
database = makeTestDatabaseProperties(),
database = DatabaseConfig(),
rpcUsers = emptyList(),
verifierType = VerifierType.InMemory,
useHTTPS = false,

View File

@ -23,6 +23,7 @@ import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.internal.cordapp.CordappProviderImpl
import net.corda.node.services.api.MonitoringService
import net.corda.node.services.api.ServiceHubInternal
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.node.services.network.NetworkMapCacheImpl
import net.corda.node.services.persistence.DBCheckpointStorage
@ -37,9 +38,11 @@ import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.*
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import org.assertj.core.api.Assertions.assertThat
import org.junit.*
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.nio.file.Paths
import java.security.PublicKey
import java.time.Clock
@ -90,8 +93,7 @@ class NodeSchedulerServiceTest : SingletonSerializeAsToken() {
smmHasRemovedAllFlows = CountDownLatch(1)
calls = 0
val dataSourceProps = makeTestDataSourceProperties()
val databaseProperties = makeTestDatabaseProperties()
database = configureDatabase(dataSourceProps, databaseProperties, rigorousMock())
database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock())
val identityService = InMemoryIdentityService(trustRoot = DEV_TRUST_ROOT)
kms = MockKeyManagementService(identityService, ALICE_KEY)
val configuration = testNodeConfiguration(Paths.get("."), CordaX500Name("Alice", "London", "GB"))

View File

@ -7,6 +7,7 @@ import net.corda.core.internal.concurrent.openFuture
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.services.RPCUserService
import net.corda.node.services.RPCUserServiceImpl
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.configureWithDevSSLCertificate
import net.corda.node.services.network.NetworkMapCacheImpl
@ -18,7 +19,6 @@ import net.corda.node.utilities.configureDatabase
import net.corda.testing.*
import net.corda.testing.node.MockServices.Companion.MOCK_VERSION_INFO
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.After
@ -67,7 +67,7 @@ class ArtemisMessagingTests {
baseDirectory = baseDirectory,
myLegalName = ALICE.name)
LogHelper.setLevel(PersistentUniquenessProvider::class)
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), rigorousMock())
database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock())
networkMapRegistrationFuture = doneFuture(Unit)
networkMapCache = NetworkMapCacheImpl(PersistentNetworkMapCache(database), rigorousMock())
}

View File

@ -4,13 +4,13 @@ import com.google.common.primitives.Ints
import net.corda.core.serialization.SerializedBytes
import net.corda.node.services.api.Checkpoint
import net.corda.node.services.api.CheckpointStorage
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.testing.LogHelper
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.rigorousMock
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
@ -31,13 +31,14 @@ class DBCheckpointStorageTests {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
lateinit var checkpointStorage: DBCheckpointStorage
lateinit var database: CordaPersistence
private lateinit var checkpointStorage: DBCheckpointStorage
private lateinit var database: CordaPersistence
@Before
fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class)
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), rigorousMock())
database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock())
newCheckpointStorage()
}

View File

@ -6,11 +6,11 @@ import net.corda.core.crypto.SecureHash
import net.corda.core.crypto.SignatureMetadata
import net.corda.core.crypto.TransactionSignature
import net.corda.core.node.StatesToRecord
import net.corda.core.node.services.VaultService
import net.corda.core.toFuture
import net.corda.core.transactions.SignedTransaction
import net.corda.core.transactions.WireTransaction
import net.corda.node.services.api.VaultServiceInternal
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.services.vault.NodeVaultService
@ -19,7 +19,6 @@ import net.corda.node.utilities.configureDatabase
import net.corda.testing.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
@ -32,16 +31,16 @@ class DBTransactionStorageTests {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
lateinit var database: CordaPersistence
lateinit var transactionStorage: DBTransactionStorage
lateinit var services: MockServices
val vault: VaultService get() = services.vaultService
private lateinit var database: CordaPersistence
private lateinit var transactionStorage: DBTransactionStorage
private lateinit var services: MockServices
@Before
fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceProps = makeTestDataSourceProperties()
database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), rigorousMock())
database = configureDatabase(dataSourceProps, DatabaseConfig(), rigorousMock())
database.transaction {
services = object : MockServices(BOB_KEY) {
override val vaultService: VaultServiceInternal

View File

@ -25,6 +25,7 @@ import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.schemas.SampleCashSchemaV2
import net.corda.finance.schemas.SampleCashSchemaV3
import net.corda.finance.utils.sumCash
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.vault.VaultSchemaV1
import net.corda.node.utilities.CordaPersistence
@ -36,7 +37,6 @@ import net.corda.testing.contracts.fillWithSomeTestDeals
import net.corda.testing.contracts.fillWithSomeTestLinearStates
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.node.MockServices.Companion.makeTestIdentityService
import net.corda.testing.schemas.DummyLinearStateSchemaV1
import net.corda.testing.schemas.DummyLinearStateSchemaV2
@ -84,8 +84,7 @@ class HibernateConfigurationTest {
issuerServices = MockServices(cordappPackages, DUMMY_CASH_ISSUER_NAME, DUMMY_CASH_ISSUER_KEY)
notaryServices = MockServices(cordappPackages, DUMMY_NOTARY.name, DUMMY_NOTARY_KEY)
val dataSourceProps = makeTestDataSourceProperties()
val defaultDatabaseProperties = makeTestDatabaseProperties()
database = configureDatabase(dataSourceProps, defaultDatabaseProperties, makeTestIdentityService())
database = configureDatabase(dataSourceProps, DatabaseConfig(), makeTestIdentityService())
database.transaction {
hibernateConfig = database.hibernateConfig
// `consumeCash` expects we can self-notarise transactions

View File

@ -13,12 +13,12 @@ import net.corda.core.node.services.vault.AttachmentQueryCriteria
import net.corda.core.node.services.vault.AttachmentSort
import net.corda.core.node.services.vault.Builder
import net.corda.core.node.services.vault.Sort
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.testing.LogHelper
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.rigorousMock
import org.junit.After
import org.junit.Before
@ -36,15 +36,15 @@ import kotlin.test.assertNull
class NodeAttachmentStorageTest {
// Use an in memory file system for testing attachment storage.
lateinit var fs: FileSystem
lateinit var database: CordaPersistence
private lateinit var fs: FileSystem
private lateinit var database: CordaPersistence
@Before
fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class)
val dataSourceProperties = makeTestDataSourceProperties()
database = configureDatabase(dataSourceProperties, makeTestDatabaseProperties(), rigorousMock())
database = configureDatabase(dataSourceProperties, DatabaseConfig(), rigorousMock())
fs = Jimfs.newFileSystem(Configuration.unix())
}
@ -82,9 +82,9 @@ class NodeAttachmentStorageTest {
@Test
fun `metadata can be used to search`() {
val (jarA,hashA) = makeTestJar()
val (jarB,hashB) = makeTestJar(listOf(Pair("file","content")))
val (jarC,hashC) = makeTestJar(listOf(Pair("magic_file","magic_content_puff")))
val (jarA, _) = makeTestJar()
val (jarB, hashB) = makeTestJar(listOf(Pair("file","content")))
val (jarC, hashC) = makeTestJar(listOf(Pair("magic_file","magic_content_puff")))
database.transaction {
val storage = NodeAttachmentService(MetricRegistry())

View File

@ -11,13 +11,13 @@ import net.corda.core.schemas.MappedSchema
import net.corda.core.schemas.PersistentState
import net.corda.core.schemas.QueryableState
import net.corda.node.services.api.SchemaService
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.utilities.DatabaseTransactionManager
import net.corda.node.utilities.configureDatabase
import net.corda.testing.LogHelper
import net.corda.testing.MEGA_CORP
import net.corda.testing.contracts.DummyContract
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.rigorousMock
import org.junit.After
import org.junit.Before
@ -25,9 +25,7 @@ import org.junit.Test
import rx.subjects.PublishSubject
import kotlin.test.assertEquals
class HibernateObserverTests {
@Before
fun setUp() {
LogHelper.setLevel(HibernateObserver::class)
@ -51,9 +49,8 @@ class HibernateObserverTests {
get() = throw UnsupportedOperationException()
}
// This method does not use back quotes for a nice name since it seems to kill the kotlin compiler.
@Test
fun testChildObjectsArePersisted() {
fun `test child objects are persisted`() {
val testSchema = TestSchema
val rawUpdatesPublisher = PublishSubject.create<Vault.Update<ContractState>>()
val schemaService = object : SchemaService {
@ -68,7 +65,7 @@ class HibernateObserverTests {
return parent
}
}
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), rigorousMock(), schemaService)
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock(), schemaService)
HibernateObserver.install(rawUpdatesPublisher, database.hibernateConfig)
database.transaction {
rawUpdatesPublisher.onNext(Vault.Update(emptySet(), setOf(StateAndRef(TransactionState(TestState(), DummyContract.PROGRAM_ID, MEGA_CORP), StateRef(SecureHash.sha256("dummy"), 0)))))

View File

@ -10,16 +10,18 @@ import net.corda.core.internal.concurrent.asCordaFuture
import net.corda.core.internal.concurrent.transpose
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.DatabaseTransaction
import net.corda.node.utilities.configureDatabase
import net.corda.testing.LogHelper
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.freeLocalHostAndPort
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.rigorousMock
import org.junit.*
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import java.util.concurrent.CompletableFuture
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@ -30,8 +32,8 @@ class DistributedImmutableMapTests {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule(true)
lateinit var cluster: List<Member>
lateinit var transaction: DatabaseTransaction
private lateinit var cluster: List<Member>
private val databases: MutableList<CordaPersistence> = mutableListOf()
@Before
@ -86,7 +88,7 @@ class DistributedImmutableMapTests {
private fun createReplica(myAddress: NetworkHostAndPort, clusterAddress: NetworkHostAndPort? = null): CompletableFuture<Member> {
val storage = Storage.builder().withStorageLevel(StorageLevel.MEMORY).build()
val address = Address(myAddress.host, myAddress.port)
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties("serverNameTablePrefix", "PORT_${myAddress.port}_"), rigorousMock())
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(serverNameTablePrefix = "PORT_${myAddress.port}_"), rigorousMock())
databases.add(database)
val stateMachineFactory = { DistributedImmutableMap(database, RaftUniquenessProvider.Companion::createMap) }

View File

@ -2,11 +2,11 @@ package net.corda.node.services.transactions
import net.corda.core.crypto.SecureHash
import net.corda.core.node.services.UniquenessException
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.testing.*
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import org.junit.After
import org.junit.Before
import org.junit.Rule
@ -18,15 +18,16 @@ class PersistentUniquenessProviderTests {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
val identity = MEGA_CORP
val txID = SecureHash.randomSHA256()
lateinit var database: CordaPersistence
private val identity = MEGA_CORP
private val txID = SecureHash.randomSHA256()
private lateinit var database: CordaPersistence
@Before
fun setUp() {
LogHelper.setLevel(PersistentUniquenessProvider::class)
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), rigorousMock())
database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock())
}
@After

View File

@ -27,15 +27,14 @@ import net.corda.finance.schemas.CashSchemaV1
import net.corda.finance.schemas.CashSchemaV1.PersistentCashState
import net.corda.finance.schemas.CommercialPaperSchemaV1
import net.corda.finance.schemas.SampleCashSchemaV3
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.testing.*
import net.corda.testing.contracts.*
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseAndMockServices
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.schemas.DummyLinearStateSchemaV1
import org.assertj.core.api.Assertions
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.*
@ -53,9 +52,16 @@ class VaultQueryTests {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
private val cordappPackages = setOf(
"net.corda.testing.contracts", "net.corda.finance.contracts",
CashSchemaV1::class.packageName, CommercialPaperSchemaV1::class.packageName, DummyLinearStateSchemaV1::class.packageName).toMutableList()
@Rule
@JvmField
val expectedEx: ExpectedException = ExpectedException.none()
private val cordappPackages = mutableListOf(
"net.corda.testing.contracts",
"net.corda.finance.contracts",
CashSchemaV1::class.packageName,
DummyLinearStateSchemaV1::class.packageName)
private lateinit var services: MockServices
private lateinit var notaryServices: MockServices
private val vaultService: VaultService get() = services.vaultService
@ -93,7 +99,7 @@ class VaultQueryTests {
@Ignore
@Test
fun createPersistentTestDb() {
val database = configureDatabase(makePersistentDataSourceProperties(), makeTestDatabaseProperties(), identitySvc)
val database = configureDatabase(makePersistentDataSourceProperties(), DatabaseConfig(), identitySvc)
setUpDb(database, 5000)
database.close()
@ -129,9 +135,6 @@ class VaultQueryTests {
return props
}
@get:Rule
val expectedEx = ExpectedException.none()!!
/**
* Query API tests
*/
@ -1597,8 +1600,8 @@ class VaultQueryTests {
val result = vaultService.queryBy<CommercialPaper.State>(criteria1)
Assertions.assertThat(result.states).hasSize(1)
Assertions.assertThat(result.statesMetadata).hasSize(1)
assertThat(result.states).hasSize(1)
assertThat(result.statesMetadata).hasSize(1)
}
}
@ -1642,8 +1645,8 @@ class VaultQueryTests {
vaultService.queryBy<CommercialPaper.State>(criteria1.and(criteria3).and(criteria2))
}
Assertions.assertThat(result.states).hasSize(1)
Assertions.assertThat(result.statesMetadata).hasSize(1)
assertThat(result.states).hasSize(1)
assertThat(result.statesMetadata).hasSize(1)
}
}

View File

@ -3,8 +3,8 @@ package net.corda.node.utilities
import com.google.common.util.concurrent.SettableFuture
import net.corda.core.internal.bufferUntilSubscribed
import net.corda.core.internal.tee
import net.corda.node.services.config.DatabaseConfig
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.rigorousMock
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
@ -18,10 +18,10 @@ class ObservablesTests {
private fun isInDatabaseTransaction(): Boolean = (DatabaseTransactionManager.currentOrNull() != null)
val toBeClosed = mutableListOf<Closeable>()
private val toBeClosed = mutableListOf<Closeable>()
fun createDatabase(): CordaPersistence {
val database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), rigorousMock())
private fun createDatabase(): CordaPersistence {
val database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock())
toBeClosed += database
return database
}

View File

@ -15,6 +15,7 @@ import net.corda.finance.contracts.FixOf
import net.corda.finance.contracts.asset.CASH
import net.corda.finance.contracts.asset.Cash
import net.corda.irs.flows.RatesFixFlow
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.utilities.CordaPersistence
import net.corda.node.utilities.configureDatabase
import net.corda.testing.*
@ -22,7 +23,6 @@ import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import net.corda.testing.node.createMockCordaService
import org.junit.After
import org.junit.Assert.*
@ -68,7 +68,7 @@ class NodeInterestRatesTest {
@Before
fun setUp() {
database = configureDatabase(makeTestDataSourceProperties(), makeTestDatabaseProperties(), rigorousMock())
database = configureDatabase(makeTestDataSourceProperties(), DatabaseConfig(), rigorousMock())
database.transaction {
oracle = createMockCordaService(services, NodeInterestRates::Oracle)
oracle.knownFixes = TEST_DATA

View File

@ -6,24 +6,24 @@ import com.nhaarman.mockito_kotlin.doCallRealMethod
import com.nhaarman.mockito_kotlin.doReturn
import com.nhaarman.mockito_kotlin.whenever
import net.corda.core.context.Actor
import net.corda.core.context.AuthServiceId
import net.corda.core.context.InvocationContext
import net.corda.core.context.Origin
import net.corda.core.context.AuthServiceId
import net.corda.core.flows.FlowLogic
import net.corda.core.identity.CordaX500Name
import net.corda.core.internal.FlowStateMachine
import net.corda.core.node.ServiceHub
import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.seconds
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.seconds
import net.corda.node.services.api.StartedNodeServices
import net.corda.node.services.config.CertChainPolicyConfig
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.config.NodeConfiguration
import net.corda.node.services.config.VerifierType
import net.corda.nodeapi.User
import net.corda.testing.node.MockServices
import net.corda.testing.node.MockServices.Companion.makeTestDataSourceProperties
import net.corda.testing.node.MockServices.Companion.makeTestDatabaseProperties
import java.nio.file.Path
/**
@ -64,7 +64,7 @@ fun testNodeConfiguration(
doReturn(emptyList<User>()).whenever(it).rpcUsers
doReturn(null).whenever(it).notary
doReturn(makeTestDataSourceProperties(myLegalName.organisation)).whenever(it).dataSourceProperties
doReturn(makeTestDatabaseProperties()).whenever(it).database
doReturn(DatabaseConfig()).whenever(it).database
doReturn("").whenever(it).emailAddress
doReturn("").whenever(it).exportJMXto
doReturn(true).whenever(it).devMode

View File

@ -21,6 +21,7 @@ import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage
import net.corda.node.services.api.VaultServiceInternal
import net.corda.node.services.api.WritableTransactionStorage
import net.corda.node.services.config.DatabaseConfig
import net.corda.node.services.identity.InMemoryIdentityService
import net.corda.node.services.keys.freshCertificate
import net.corda.node.services.keys.getSigner
@ -76,22 +77,6 @@ open class MockServices(
return props
}
/**
* Make properties appropriate for creating a Database for unit tests.
*
* @param key (optional) key of a database property to be set.
* @param value (optional) value of a database property to be set.
*/
@JvmStatic
fun makeTestDatabaseProperties(key: String? = null, value: String? = null): Properties {
val props = Properties()
props.setProperty("transactionIsolationLevel", "repeatableRead") //for other possible values see net.corda.node.utilities.CordaPeristence.parserTransactionIsolationLevel(String)
if (key != null) {
props.setProperty(key, value)
}
return props
}
/**
* Creates an instance of [InMemoryIdentityService] with [MOCK_IDENTITIES].
*/
@ -125,8 +110,7 @@ open class MockServices(
initialIdentityName: CordaX500Name): Pair<CordaPersistence, MockServices> {
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
val dataSourceProps = makeTestDataSourceProperties()
val databaseProperties = makeTestDatabaseProperties()
val database = configureDatabase(dataSourceProps, databaseProperties, identityService, NodeSchemaService(cordappLoader))
val database = configureDatabase(dataSourceProps, DatabaseConfig(), identityService, NodeSchemaService(cordappLoader))
val mockService = database.transaction {
object : MockServices(cordappLoader, initialIdentityName = initialIdentityName, keys = *(keys.toTypedArray())) {
override val identityService get() = identityService