mirror of
https://github.com/corda/corda.git
synced 2024-12-29 09:18:58 +00:00
Ability to run integration tests against standalone databases (part 2) (#109)
Commit 359610ff14
didn't fully covered:
* Integration tests extends IntegrationTest class which can run SQL scripts before and after a test and before and after test class.
*Driver.kt creates notaries without a table name prefixes (separation is achieved by using different user/schema).
*Revert wrongly altered H2 JDBC connection string for tests.
This commit is contained in:
parent
233f1fb8e2
commit
4f2d8d058e
@ -34,7 +34,7 @@ import net.corda.testing.driver.driver
|
|||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
|
||||||
class NodeMonitorModelTest {
|
class NodeMonitorModelTest : IntegrationTest() {
|
||||||
private lateinit var aliceNode: NodeInfo
|
private lateinit var aliceNode: NodeInfo
|
||||||
private lateinit var bobNode: NodeInfo
|
private lateinit var bobNode: NodeInfo
|
||||||
private lateinit var notaryParty: Party
|
private lateinit var notaryParty: Party
|
||||||
|
@ -55,7 +55,8 @@ public class CordaRPCJavaClientTest extends NodeBasedTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws ExecutionException, InterruptedException {
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
node = startNode(getALICE().getName(), 1, singletonList(rpcUser));
|
node = startNode(getALICE().getName(), 1, singletonList(rpcUser));
|
||||||
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));
|
client = new CordaRPCClient(requireNonNull(node.getInternals().getConfiguration().getRpcAddress()));
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,12 @@ import net.corda.core.messaging.startFlow
|
|||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.utilities.getOrThrow
|
import net.corda.core.utilities.getOrThrow
|
||||||
import net.corda.testing.ALICE
|
import net.corda.testing.ALICE
|
||||||
|
import net.corda.testing.IntegrationTest
|
||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
import org.assertj.core.api.Assertions.assertThatExceptionOfType
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class BlacklistKotlinClosureTest {
|
class BlacklistKotlinClosureTest : IntegrationTest() {
|
||||||
companion object {
|
companion object {
|
||||||
const val EVIL: Long = 666
|
const val EVIL: Long = 666
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,8 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
node = startNode(ALICE.name, rpcUsers = listOf(rpcUser))
|
node = startNode(ALICE.name, rpcUsers = listOf(rpcUser))
|
||||||
client = CordaRPCClient(node.internals.configuration.rpcAddress!!)
|
client = CordaRPCClient(node.internals.configuration.rpcAddress!!)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ import java.time.Duration
|
|||||||
import java.util.concurrent.*
|
import java.util.concurrent.*
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
class RPCStabilityTests {
|
class RPCStabilityTests : IntegrationTest() {
|
||||||
|
|
||||||
object DummyOps : RPCOps {
|
object DummyOps : RPCOps {
|
||||||
override val protocolVersion = 0
|
override val protocolVersion = 0
|
||||||
|
@ -27,7 +27,9 @@ import kotlin.concurrent.withLock
|
|||||||
* Custom implementations must implement this interface and declare their implementation in
|
* Custom implementations must implement this interface and declare their implementation in
|
||||||
* META-INF/services/net.corda.contracts.asset.CashSelection
|
* META-INF/services/net.corda.contracts.asset.CashSelection
|
||||||
*/
|
*/
|
||||||
abstract class AbstractCashSelection {
|
// TODO: make parameters configurable when we get CorDapp configuration.
|
||||||
|
abstract class AbstractCashSelection(private val maxRetries : Int = 8, private val retrySleep : Int = 100,
|
||||||
|
private val retryCap : Int = 2000) {
|
||||||
companion object {
|
companion object {
|
||||||
val instance = AtomicReference<AbstractCashSelection>()
|
val instance = AtomicReference<AbstractCashSelection>()
|
||||||
|
|
||||||
@ -48,10 +50,6 @@ abstract class AbstractCashSelection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// coin selection retry loop counter, sleep (msecs) and lock for selecting states
|
// coin selection retry loop counter, sleep (msecs) and lock for selecting states
|
||||||
// TODO: make parameters configurable when we get CorDapp configuration.
|
|
||||||
private val MAX_RETRIES = 8
|
|
||||||
private val RETRY_SLEEP = 100
|
|
||||||
private val RETRY_CAP = 2000
|
|
||||||
private val spendLock: ReentrantLock = ReentrantLock()
|
private val spendLock: ReentrantLock = ReentrantLock()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,13 +101,13 @@ abstract class AbstractCashSelection {
|
|||||||
withIssuerRefs: Set<OpaqueBytes> = emptySet()): List<StateAndRef<Cash.State>> {
|
withIssuerRefs: Set<OpaqueBytes> = emptySet()): List<StateAndRef<Cash.State>> {
|
||||||
val stateAndRefs = mutableListOf<StateAndRef<Cash.State>>()
|
val stateAndRefs = mutableListOf<StateAndRef<Cash.State>>()
|
||||||
|
|
||||||
for (retryCount in 1..MAX_RETRIES) {
|
for (retryCount in 1..maxRetries) {
|
||||||
if (!attemptSpend(services, amount, lockId, notary, onlyFromIssuerParties, withIssuerRefs, stateAndRefs)) {
|
if (!attemptSpend(services, amount, lockId, notary, onlyFromIssuerParties, withIssuerRefs, stateAndRefs)) {
|
||||||
log.warn("Coin selection failed on attempt $retryCount")
|
log.warn("Coin selection failed on attempt $retryCount")
|
||||||
// TODO: revisit the back off strategy for contended spending.
|
// TODO: revisit the back off strategy for contended spending.
|
||||||
if (retryCount != MAX_RETRIES) {
|
if (retryCount != maxRetries) {
|
||||||
stateAndRefs.clear()
|
stateAndRefs.clear()
|
||||||
val durationMillis = (minOf(RETRY_SLEEP.shl(retryCount), RETRY_CAP / 2) * (1.0 + Math.random())).toInt()
|
val durationMillis = (minOf(retrySleep.shl(retryCount), retryCap / 2) * (1.0 + Math.random())).toInt()
|
||||||
FlowLogic.sleep(durationMillis.millis)
|
FlowLogic.sleep(durationMillis.millis)
|
||||||
} else {
|
} else {
|
||||||
log.warn("Insufficient spendable states identified for $amount")
|
log.warn("Insufficient spendable states identified for $amount")
|
||||||
|
@ -55,7 +55,6 @@ class NodePerformanceTests : IntegrationTest() {
|
|||||||
@Before
|
@Before
|
||||||
fun before() {
|
fun before() {
|
||||||
checkQuasarAgent()
|
checkQuasarAgent()
|
||||||
super.setUp()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -26,6 +26,7 @@ import net.corda.node.services.config.NotaryConfig
|
|||||||
import net.corda.node.services.transactions.minClusterSize
|
import net.corda.node.services.transactions.minClusterSize
|
||||||
import net.corda.node.services.transactions.minCorrectReplicas
|
import net.corda.node.services.transactions.minCorrectReplicas
|
||||||
import net.corda.node.utilities.ServiceIdentityGenerator
|
import net.corda.node.utilities.ServiceIdentityGenerator
|
||||||
|
import net.corda.testing.IntegrationTest
|
||||||
import net.corda.testing.chooseIdentity
|
import net.corda.testing.chooseIdentity
|
||||||
import net.corda.testing.common.internal.NetworkParametersCopier
|
import net.corda.testing.common.internal.NetworkParametersCopier
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
@ -41,7 +42,7 @@ import java.nio.file.Paths
|
|||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
class BFTNotaryServiceTests {
|
class BFTNotaryServiceTests : IntegrationTest() {
|
||||||
private lateinit var mockNet: MockNetwork
|
private lateinit var mockNet: MockNetwork
|
||||||
private lateinit var notary: Party
|
private lateinit var notary: Party
|
||||||
private lateinit var node: StartedNode<MockNode>
|
private lateinit var node: StartedNode<MockNode>
|
||||||
|
@ -13,6 +13,7 @@ import net.corda.testing.contracts.DummyContract
|
|||||||
import net.corda.testing.contracts.DummyState
|
import net.corda.testing.contracts.DummyState
|
||||||
import net.corda.testing.driver.driver
|
import net.corda.testing.driver.driver
|
||||||
import net.corda.testing.dummyCommand
|
import net.corda.testing.dummyCommand
|
||||||
|
import net.corda.testing.IntegrationTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ import kotlin.test.assertEquals
|
|||||||
* Check that we can add lots of large attachments to a transaction and that it works OK, e.g. does not hit the
|
* Check that we can add lots of large attachments to a transaction and that it works OK, e.g. does not hit the
|
||||||
* transaction size limit (which should only consider the hashes).
|
* transaction size limit (which should only consider the hashes).
|
||||||
*/
|
*/
|
||||||
class LargeTransactionsTest {
|
class LargeTransactionsTest : IntegrationTest() {
|
||||||
@StartableByRPC
|
@StartableByRPC
|
||||||
@InitiatingFlow
|
@InitiatingFlow
|
||||||
class SendLargeTransactionFlow(private val hash1: SecureHash,
|
class SendLargeTransactionFlow(private val hash1: SecureHash,
|
||||||
|
@ -889,9 +889,7 @@ class DriverDSL(
|
|||||||
providedName = nodeNames[0],
|
providedName = nodeNames[0],
|
||||||
rpcUsers = spec.rpcUsers,
|
rpcUsers = spec.rpcUsers,
|
||||||
verifierType = spec.verifierType,
|
verifierType = spec.verifierType,
|
||||||
customOverrides = notaryConfig(clusterAddress) + mapOf(
|
customOverrides = notaryConfig(clusterAddress)
|
||||||
"database.serverNameTablePrefix" to nodeNames[0].toString().replace(Regex("[^0-9A-Za-z]+"), "")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// All other nodes will join the cluster
|
// All other nodes will join the cluster
|
||||||
@ -901,9 +899,7 @@ class DriverDSL(
|
|||||||
providedName = it,
|
providedName = it,
|
||||||
rpcUsers = spec.rpcUsers,
|
rpcUsers = spec.rpcUsers,
|
||||||
verifierType = spec.verifierType,
|
verifierType = spec.verifierType,
|
||||||
customOverrides = notaryConfig(nodeAddress, clusterAddress) + mapOf(
|
customOverrides = notaryConfig(nodeAddress, clusterAddress)
|
||||||
"database.serverNameTablePrefix" to it.toString().replace(Regex("[^0-9A-Za-z]+"), "")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import net.corda.node.services.config.configOf
|
|||||||
import net.corda.node.services.config.parseAsNodeConfiguration
|
import net.corda.node.services.config.parseAsNodeConfiguration
|
||||||
import net.corda.node.services.config.plus
|
import net.corda.node.services.config.plus
|
||||||
import net.corda.nodeapi.User
|
import net.corda.nodeapi.User
|
||||||
|
import net.corda.testing.IntegrationTest
|
||||||
import net.corda.testing.SerializationEnvironmentRule
|
import net.corda.testing.SerializationEnvironmentRule
|
||||||
import net.corda.testing.common.internal.NetworkParametersCopier
|
import net.corda.testing.common.internal.NetworkParametersCopier
|
||||||
import net.corda.testing.common.internal.testNetworkParameters
|
import net.corda.testing.common.internal.testNetworkParameters
|
||||||
@ -31,7 +32,7 @@ import java.util.concurrent.Executors
|
|||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
// TODO Some of the logic here duplicates what's in the driver
|
// TODO Some of the logic here duplicates what's in the driver
|
||||||
abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyList()) {
|
abstract class NodeBasedTest(private val cordappPackages: List<String> = emptyList()) : IntegrationTest() {
|
||||||
companion object {
|
companion object {
|
||||||
private val WHITESPACE = "\\s++".toRegex()
|
private val WHITESPACE = "\\s++".toRegex()
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@ open class MockServices(
|
|||||||
|
|
||||||
private fun readDatabaseConfig(nodeName: String? = null, postifx: String? = null): Config {
|
private fun readDatabaseConfig(nodeName: String? = null, postifx: String? = null): Config {
|
||||||
val standarizedNodeName = if (nodeName!= null) nodeName.replace(" ", "").replace("-", "_") else null
|
val standarizedNodeName = if (nodeName!= null) nodeName.replace(" ", "").replace("-", "_") else null
|
||||||
|
//in case of H2, the same db instance runs for all integration tests, so adding additional variable postfix to use unique db user/schema each time
|
||||||
val h2InstanceName = if (postifx != null) standarizedNodeName + "_" + postifx else standarizedNodeName
|
val h2InstanceName = if (postifx != null) standarizedNodeName + "_" + postifx else standarizedNodeName
|
||||||
val parseOptions = ConfigParseOptions.defaults()
|
val parseOptions = ConfigParseOptions.defaults()
|
||||||
val databaseConfig = ConfigFactory.parseResources(System.getProperty("databaseProvider") + ".conf", parseOptions.setAllowMissing(true))
|
val databaseConfig = ConfigFactory.parseResources(System.getProperty("databaseProvider") + ".conf", parseOptions.setAllowMissing(true))
|
||||||
@ -70,7 +71,7 @@ open class MockServices(
|
|||||||
val nodeOrganizationNameConfig = if (standarizedNodeName != null) configOf("nodeOrganizationName" to standarizedNodeName) else ConfigFactory.empty()
|
val nodeOrganizationNameConfig = if (standarizedNodeName != null) configOf("nodeOrganizationName" to standarizedNodeName) else ConfigFactory.empty()
|
||||||
val defaultProps = Properties()
|
val defaultProps = Properties()
|
||||||
defaultProps.setProperty("dataSourceProperties.dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
defaultProps.setProperty("dataSourceProperties.dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
|
||||||
defaultProps.setProperty("dataSourceProperties.dataSource.url", "jdbc:h2:mem:${h2InstanceName}_persistence;LOCK_TIMEOUT=100;DB_CLOSE_ON_EXIT=TRUE")//;TRACE_LEVEL_SYSTEM_OUT=4")
|
defaultProps.setProperty("dataSourceProperties.dataSource.url", "jdbc:h2:mem:${h2InstanceName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
|
||||||
defaultProps.setProperty("dataSourceProperties.dataSource.user", "sa")
|
defaultProps.setProperty("dataSourceProperties.dataSource.user", "sa")
|
||||||
defaultProps.setProperty("dataSourceProperties.dataSource.password", "")
|
defaultProps.setProperty("dataSourceProperties.dataSource.password", "")
|
||||||
val defaultConfig = ConfigFactory.parseProperties(defaultProps, parseOptions)
|
val defaultConfig = ConfigFactory.parseProperties(defaultProps, parseOptions)
|
||||||
|
Loading…
Reference in New Issue
Block a user