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:
szymonsztuka 2017-11-15 14:04:48 +00:00 committed by GitHub
parent 233f1fb8e2
commit 4f2d8d058e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 24 additions and 24 deletions

View File

@ -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

View File

@ -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()));
} }

View File

@ -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
} }

View File

@ -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!!)
} }

View File

@ -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

View File

@ -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")

View File

@ -55,7 +55,6 @@ class NodePerformanceTests : IntegrationTest() {
@Before @Before
fun before() { fun before() {
checkQuasarAgent() checkQuasarAgent()
super.setUp()
} }
@Test @Test

View File

@ -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>

View File

@ -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,

View File

@ -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]+"), "")
)
) )
} }

View File

@ -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()
} }

View File

@ -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)