SQL Azure and SQL Server database integration tests (#115)

* Integration test are parameterised (extends IntegrationTest) to run against a remote database with 4 db scripts run @BeforeClass, @Before, @After and @AfterClass.
* SQL script for SQL Azure and SQL Server databases and templates of JDBC configuration.
This commit is contained in:
szymonsztuka 2017-12-01 17:17:51 +00:00 committed by GitHub
parent d81e4809bb
commit 709b3791a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
50 changed files with 606 additions and 105 deletions

View File

@ -18,6 +18,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../../testing/test-utils/src/main/resources')
}
}
}

View File

@ -31,6 +31,7 @@ import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.*
import net.corda.testing.driver.driver
import org.junit.ClassRule
import org.junit.Test
import rx.Observable
@ -50,6 +51,12 @@ class NodeMonitorModelTest : IntegrationTest() {
private lateinit var networkMapUpdates: Observable<NetworkMapCache.MapChange>
private lateinit var newNode: (CordaX500Name) -> NodeInfo
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, CHARLIE, DUMMY_NOTARY)
.map { it.toDatabaseSchemaNames("","_10000","_10003") }.flatten().toTypedArray())
}
private fun setup(runTest: () -> Unit) {
driver(extraCordappPackagesToScan = listOf("net.corda.finance")) {
val cashUser = User("user1", "test", permissions = setOf(

View File

@ -27,6 +27,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/java')
}
resources {
srcDir file('../../testing/test-utils/src/main/resources')
}
}
smokeTest {
kotlin {

View File

@ -12,9 +12,12 @@ import net.corda.node.internal.Node;
import net.corda.node.internal.StartedNode;
import net.corda.nodeapi.User;
import net.corda.testing.CoreTestUtils;
import net.corda.testing.IntegrationTestKt;
import net.corda.testing.IntegrationTestSchemas;
import net.corda.testing.internal.NodeBasedTest;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import java.io.IOException;
@ -29,12 +32,17 @@ import static net.corda.finance.contracts.GetBalances.getCashBalance;
import static net.corda.node.services.Permissions.invokeRpc;
import static net.corda.node.services.Permissions.startFlow;
import static net.corda.testing.TestConstants.getALICE;
import static net.corda.testing.TestConstants.getDUMMY_NOTARY;
public class CordaRPCJavaClientTest extends NodeBasedTest {
public CordaRPCJavaClientTest() {
super(Arrays.asList("net.corda.finance.contracts", CashSchemaV1.class.getPackage().getName()));
}
@ClassRule
public static IntegrationTestSchemas databaseSchemas = new IntegrationTestSchemas(IntegrationTestKt.toDatabaseSchemaName(getALICE()),
IntegrationTestKt.toDatabaseSchemaName(getDUMMY_NOTARY()));
private List<String> perms = Arrays.asList(
startFlow(CashPaymentFlow.class),
startFlow(CashIssueFlow.class),

View File

@ -7,15 +7,18 @@ import net.corda.core.flows.StartableByRPC
import net.corda.core.messaging.startFlow
import net.corda.core.serialization.CordaSerializable
import net.corda.core.utilities.getOrThrow
import net.corda.testing.ALICE
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.driver.driver
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.ClassRule
import org.junit.Test
class BlacklistKotlinClosureTest : IntegrationTest() {
companion object {
const val EVIL: Long = 666
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName(), DUMMY_NOTARY.toDatabaseSchemaName())
}
@StartableByRPC

View File

@ -28,6 +28,7 @@ import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.After
import org.junit.Before
import org.junit.ClassRule
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
@ -49,6 +50,10 @@ class CordaRPCClientTest : NodeBasedTest(listOf("net.corda.finance.contracts", C
private fun login(username: String, password: String, externalTrace: Trace? = null, impersonatedActor: Actor? = null) {
connection = client.start(username, password, externalTrace, impersonatedActor)
}
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName())
}
@Before
override fun setUp() {

View File

@ -12,14 +12,14 @@ import net.corda.core.serialization.serialize
import net.corda.core.utilities.*
import net.corda.node.services.messaging.RPCServerConfiguration
import net.corda.nodeapi.RPCApi
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.driver.poll
import net.corda.testing.internal.*
import org.apache.activemq.artemis.api.core.SimpleString
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.ClassRule
import org.junit.Rule
import org.junit.Test
import rx.Observable
@ -39,6 +39,12 @@ class RPCStabilityTests : IntegrationTest() {
pool.shutdown()
}
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_BANK_A)
.map { it.toDatabaseSchemaNames("","_10000","_10003","_10012") }.flatten().toTypedArray())
}
object DummyOps : RPCOps {
override val protocolVersion = 0
}

View File

@ -24,6 +24,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../../testing/test-utils/src/main/resources')
}
}
}

View File

@ -20,6 +20,9 @@ import org.junit.Test
import kotlin.test.assertEquals
class IntegrationTestingTutorial : IntegrationTest() {
override val databaseSchemas: MutableList<String>
get() = listOf(ALICE, BOB, DUMMY_NOTARY).map { it.toDatabaseSchemaName() }.toMutableList()
@Test
fun `alice bob cash exchange example`() {
// START 1

View File

@ -17,6 +17,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../../testing/test-utils/src/main/resources')
}
}
}

View File

@ -4,12 +4,18 @@ import net.corda.core.messaging.startFlow
import net.corda.core.utilities.getOrThrow
import net.corda.finance.EUR
import net.corda.finance.USD
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.driver.driver
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
class CashConfigDataFlowTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_BANK_A)
.map { it.toDatabaseSchemaNames("","_10000","_10003") }.flatten().toTypedArray())
}
@Test
fun `issuable currencies are read in from node config`() {
driver {

View File

@ -14,7 +14,7 @@ import java.util.*
/**
* SQL Server / SQL Azure
*/
class CashSelectionSQLServerImpl : AbstractCashSelection() {
class CashSelectionSQLServerImpl : AbstractCashSelection(maxRetries = 16, retrySleep = 1000, retryCap = 5000) {
companion object {
val JDBC_DRIVER_NAME = "Microsoft JDBC Driver 6.2 for SQL Server"

View File

@ -35,6 +35,7 @@ sourceSets {
}
resources {
srcDir file('src/integration-test/resources')
srcDir file('../../testing/test-utils/src/main/resources')
}
}
}

View File

@ -9,18 +9,23 @@ import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.NodeStartup
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.ALICE
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.common.internal.ProjectStructure.projectRootDir
import net.corda.testing.driver.driver
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Assertions.assertThatThrownBy
import org.junit.ClassRule
import org.junit.Test
import java.io.*
import java.nio.file.Files
import kotlin.test.assertEquals
class BootTests : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_BANK_A)
.map { it.toDatabaseSchemaNames("", "_10000","_10003") }.flatten().toTypedArray())
}
@Test
fun `java deserialization is disabled`() {

View File

@ -9,15 +9,18 @@ import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.IntegrationTest
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.driver.driver
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
class CordappScanningDriverTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName(), BOB.toDatabaseSchemaName())
}
@Test
fun `sub-classed initiated flow pointing to the same initiating flow as its super-class`() {
val user = User("u", "p", setOf(startFlow<ReceiveFlow>()))

View File

@ -14,8 +14,7 @@ import net.corda.finance.flows.CashIssueFlow
import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
import net.corda.testing.node.NotarySpec
@ -24,6 +23,7 @@ import net.corda.testing.internal.performance.startPublishingFixedRateInjector
import net.corda.testing.internal.performance.startReporter
import net.corda.testing.internal.performance.startTightLoopInjector
import org.junit.Before
import org.junit.ClassRule
import org.junit.Ignore
import org.junit.Test
import java.lang.management.ManagementFactory
@ -40,6 +40,12 @@ private fun checkQuasarAgent() {
@Ignore("Run these locally")
class NodePerformanceTests : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*DUMMY_NOTARY.toDatabaseSchemaNames("_0", "_1", "_2").toTypedArray(),
DUMMY_BANK_A.toDatabaseSchemaName())
}
@StartableByRPC
class EmptyFlow : FlowLogic<Unit>() {
@Suspendable

View File

@ -1,8 +1,9 @@
package net.corda.node
import com.google.common.base.Stopwatch
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.driver.driver
import org.junit.ClassRule
import org.junit.Ignore
import org.junit.Test
import java.util.*
@ -10,7 +11,10 @@ import java.util.concurrent.TimeUnit
@Ignore("Only use locally")
class NodeStartupPerformanceTests : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_BANK_A).map { it.toDatabaseSchemaName() }.toTypedArray())
}
// Measure the startup time of nodes. Note that this includes an RPC roundtrip, which causes e.g. Kryo initialisation.
@Test
fun `single node startup time`() {

View File

@ -10,24 +10,29 @@ import net.corda.core.utilities.ProgressTracker
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.nodeapi.User
import net.corda.testing.ALICE
import net.corda.testing.driver.driver
import org.bouncycastle.util.io.Streams
import org.junit.Test
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.testing.*
import java.net.ConnectException
import kotlin.test.assertTrue
import kotlin.test.fail
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import java.util.regex.Pattern
class SSHServerTest {
class SSHServerTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName())
}
@Test()
fun `ssh server does not start be default`() {
val user = User("u", "p", setOf())
// The driver will automatically pick up the annotated flows below
driver() {
driver {
val node = startNode(providedName = ALICE.name, rpcUsers = listOf(user))
node.getOrThrow()

View File

@ -20,7 +20,6 @@ import net.corda.node.internal.cordapp.CordappProviderImpl
import net.corda.testing.*
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.SerializationEnvironmentRule
import net.corda.testing.IntegrationTest
import net.corda.testing.driver.DriverDSLExposedInterface
import net.corda.testing.driver.NodeHandle
@ -28,12 +27,14 @@ import net.corda.testing.driver.driver
import net.corda.testing.node.MockServices
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.ClassRule
import org.junit.Test
import java.net.URLClassLoader
import java.nio.file.Files
import kotlin.test.assertFailsWith
class AttachmentLoadingTests : IntegrationTest() {
private class Services : MockServices() {
private val provider = CordappProviderImpl(CordappLoader.createDevMode(listOf(isolatedJAR)), attachments)
private val cordapp get() = provider.cordapps.first()
@ -43,6 +44,10 @@ class AttachmentLoadingTests : IntegrationTest() {
}
private companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
.map { it.toDatabaseSchemaName() }.toTypedArray())
private val logger = contextLogger()
val isolatedJAR = AttachmentLoadingTests::class.java.getResource("isolated.jar")!!
val ISOLATED_CONTRACT_ID = "net.corda.finance.contracts.isolated.AnotherDummyContract"

View File

@ -27,20 +27,27 @@ import net.corda.node.services.transactions.minCorrectReplicas
import net.corda.node.utilities.ServiceIdentityGenerator
import net.corda.testing.IntegrationTest
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.dummyCommand
import net.corda.testing.node.MockNetwork
import net.corda.testing.node.MockNetwork.MockNode
import net.corda.testing.node.MockNodeParameters
import net.corda.testing.startFlow
import org.junit.After
import org.junit.Before
import org.junit.ClassRule
import org.junit.Test
import java.nio.file.Paths
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class BFTNotaryServiceTests : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas("node_0", "node_1", "node_2", "node_3", "node_4", "node_5",
"node_6", "node_7", "node_8", "node_9")
}
private lateinit var mockNet: MockNetwork
private lateinit var notary: Party
private lateinit var node: StartedNode<MockNode>

View File

@ -21,6 +21,7 @@ import net.corda.testing.driver.driver
import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.NotarySpec
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
import rx.Observable
import java.util.*
@ -31,7 +32,11 @@ class DistributedServiceTests : IntegrationTest() {
private lateinit var aliceProxy: CordaRPCOps
private lateinit var raftNotaryIdentity: Party
private lateinit var notaryStateMachines: Observable<Pair<Party, StateMachineUpdate>>
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*DUMMY_NOTARY.toDatabaseSchemaNames("_0", "_1", "_2").toTypedArray(),
ALICE.toDatabaseSchemaName())
}
private fun setup(testBlock: () -> Unit) {
val testUser = User("test", "test", permissions = setOf(
startFlow<CashIssueFlow>(),

View File

@ -12,22 +12,24 @@ import net.corda.core.transactions.TransactionBuilder
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.IntegrationTest
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
import net.corda.testing.dummyCommand
import net.corda.testing.startFlow
import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.NotarySpec
import org.junit.ClassRule
import org.junit.Test
import java.util.*
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
class RaftNotaryServiceTests : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas( "RAFTNotaryService_0", "RAFTNotaryService_1", "RAFTNotaryService_2",
DUMMY_BANK_A.toDatabaseSchemaName())
}
private val notaryName = CordaX500Name(RaftValidatingNotaryService.id, "RAFT Notary Service", "London", "GB")
@Test

View File

@ -6,16 +6,18 @@ import net.corda.core.node.NodeInfo
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.DUMMY_REGULATOR
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.internal.NodeBasedTest
import org.junit.Before
import org.junit.ClassRule
import org.junit.Test
import kotlin.test.assertEquals
class PersistentNetworkMapCacheTest : NodeBasedTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(DUMMY_REGULATOR, ALICE, BOB).map { it.toDatabaseSchemaName() }.toTypedArray())
}
private val partiesList = listOf(DUMMY_REGULATOR, ALICE, BOB)
private val addressesMap = HashMap<CordaX500Name, NetworkHostAndPort>()
private val infos = HashSet<NodeInfo>()

View File

@ -7,15 +7,18 @@ import net.corda.core.flows.InitiatingFlow
import net.corda.core.identity.Party
import net.corda.core.utilities.getOrThrow
import net.corda.core.utilities.unwrap
import net.corda.testing.ALICE
import net.corda.testing.BOB
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.internal.NodeBasedTest
import net.corda.testing.startFlow
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
class FlowVersioningTest : NodeBasedTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName(), BOB.toDatabaseSchemaName())
}
@Test
fun `getFlowContext returns the platform version for core flows`() {
val alice = startNode(ALICE.name, platformVersion = 2)

View File

@ -13,8 +13,7 @@ import net.corda.testing.*
import net.corda.testing.contracts.DummyContract
import net.corda.testing.contracts.DummyState
import net.corda.testing.driver.driver
import net.corda.testing.dummyCommand
import net.corda.testing.IntegrationTest
import org.junit.ClassRule
import org.junit.Test
import kotlin.test.assertEquals
@ -23,6 +22,11 @@ import kotlin.test.assertEquals
* transaction size limit (which should only consider the hashes).
*/
class LargeTransactionsTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_NOTARY).map { it.toDatabaseSchemaName() }.toTypedArray())
}
@StartableByRPC
@InitiatingFlow
class SendLargeTransactionFlow(private val hash1: SecureHash,

View File

@ -0,0 +1,40 @@
package net.corda.node.services.vault
import net.corda.testing.*
import org.junit.*
class VaultQueryIntegrationTests : VaultQueryTests() {
private val adapter = object: IntegrationTest() {
}
@Before
override fun setUp() {
adapter.setUp()
super.setUp()
}
@After
override fun tearDown() {
adapter.tearDown()
super.tearDown()
}
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(MEGA_CORP.toDatabaseSchemaName())
@BeforeClass
@JvmStatic
fun globalSetUp() {
IntegrationTest.globalSetUp()
}
@AfterClass
@JvmStatic
fun globalTearDown() {
IntegrationTest.globalTearDown()
}
}
}

View File

@ -31,8 +31,7 @@ import org.apache.activemq.artemis.api.core.ActiveMQNonExistentQueueException
import org.apache.activemq.artemis.api.core.ActiveMQSecurityException
import org.apache.activemq.artemis.api.core.SimpleString
import org.assertj.core.api.Assertions.assertThatExceptionOfType
import org.junit.After
import org.junit.Before
import org.junit.ClassRule
import org.junit.Test
import java.util.*
import kotlin.test.assertEquals
@ -42,13 +41,17 @@ import kotlin.test.assertEquals
* the attacker to [alice].
*/
abstract class MQSecurityTest : NodeBasedTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName(), BOB.toDatabaseSchemaName())
}
val rpcUser = User("user1", "pass", permissions = emptySet())
lateinit var alice: StartedNode<Node>
lateinit var attacker: SimpleMQClient
private val clients = ArrayList<SimpleMQClient>()
@Before
fun start() {
override fun setUp() {
super.setUp()
alice = startNode(ALICE.name, rpcUsers = extraRPCUsers + rpcUser)
attacker = createAttacker()
startAttacker(attacker)
@ -60,9 +63,10 @@ abstract class MQSecurityTest : NodeBasedTest() {
abstract fun startAttacker(attacker: SimpleMQClient)
@After
fun stopClients() {
override fun tearDown() {
rpcConnections.forEach { it.forceClose() }
clients.forEach { it.stop() }
super.tearDown()
}
@Test
@ -145,11 +149,6 @@ abstract class MQSecurityTest : NodeBasedTest() {
return CordaRPCClient(target).start(rpcUser.username, rpcUser.password).also { rpcConnections.add(it) }.proxy
}
@After
fun closeRPCConnections() {
rpcConnections.forEach { it.forceClose() }
}
fun loginToRPCAndGetClientQueue(): String {
loginToRPC(alice.internals.configuration.rpcAddress!!, rpcUser)
val clientQueueQuery = SimpleString("${RPCApi.RPC_CLIENT_QUEUE_NAME_PREFIX}.${rpcUser.username}.*")

View File

@ -16,15 +16,14 @@ import net.corda.node.internal.Node
import net.corda.node.internal.StartedNode
import net.corda.node.services.messaging.*
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.testing.ALICE
import net.corda.testing.IntegrationTest
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.driver.DriverDSLExposedInterface
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
import net.corda.testing.node.ClusterSpec
import net.corda.testing.node.NotarySpec
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
import java.util.*
import java.util.concurrent.CountDownLatch
@ -32,7 +31,10 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
class P2PMessagingTest : IntegrationTest() {
private companion object {
private companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(ALICE.toDatabaseSchemaName(), "DistributedService_0", "DistributedService_1")
val DISTRIBUTED_SERVICE_NAME = CordaX500Name(RaftValidatingNotaryService.id, "DistributedService", "London", "GB")
}

View File

@ -20,10 +20,10 @@ import net.corda.core.utilities.getOrThrow
import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.IntegrationTest
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.driver.driver
import org.junit.Assume.assumeFalse
import org.junit.ClassRule
import org.junit.Test
import java.lang.management.ManagementFactory
import javax.persistence.Column
@ -33,6 +33,12 @@ import kotlin.test.assertEquals
import kotlin.test.assertNotNull
class NodeStatePersistenceTests : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(ALICE, BOB, DUMMY_BANK_A)
.map { it.toDatabaseSchemaNames("", "_10000","_10003","_10006") }.flatten().toTypedArray(),
DUMMY_NOTARY.toDatabaseSchemaName())
}
@Test
fun `persistent state survives node restart`() {
// Temporary disable this test when executed on Windows. It is known to be sporadically failing.

View File

@ -49,7 +49,7 @@ import java.time.ZoneOffset
import java.time.temporal.ChronoUnit
import java.util.*
class VaultQueryTests {
open class VaultQueryTests {
@Rule
@JvmField
val testSerialization = SerializationEnvironmentRule()
@ -77,7 +77,7 @@ class VaultQueryTests {
private val CASH_NOTARY_IDENTITY: PartyAndCertificate get() = getTestPartyAndCertificate(CASH_NOTARY.nameOrNull(), CASH_NOTARY_KEY.public)
@Before
fun setUp() {
open fun setUp() {
// register additional identities
val databaseAndServices = makeTestDatabaseAndMockServices(keys = listOf(MEGA_CORP_KEY, DUMMY_NOTARY_KEY),
cordappPackages = cordappPackages)
@ -94,7 +94,7 @@ class VaultQueryTests {
}
@After
fun tearDown() {
open fun tearDown() {
database.close()
}
@ -1651,7 +1651,7 @@ class VaultQueryTests {
@Test
fun `unconsumed linear heads for linearId between two timestamps for a given external id`() {
val start = Instant.now()
val end = start.plus(1, ChronoUnit.SECONDS)
val end = start.plus(3, ChronoUnit.SECONDS)
database.transaction {
vaultFiller.fillWithSomeTestLinearStates(1, "TEST1")

View File

@ -14,6 +14,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../testing/test-utils/src/main/resources')
}
}
}

View File

@ -5,15 +5,20 @@ import net.corda.core.utilities.getOrThrow
import net.corda.node.services.Permissions.Companion.invokeRpc
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.driver.PortAllocation
import net.corda.testing.driver.driver
import org.junit.ClassRule
import org.junit.Test
import java.util.concurrent.CompletableFuture.supplyAsync
class AttachmentDemoTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
.map { it.toDatabaseSchemaName() }.toTypedArray())
}
// run with a 10,000,000 bytes in-memory zip file. In practice, a slightly bigger file will be used (~10,002,000 bytes).
// Force INFO logging to prevent printing 10MB arrays in logfiles
@Test

View File

@ -14,6 +14,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../testing/test-utils/src/main/resources')
}
}
}

View File

@ -13,9 +13,16 @@ import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.*
import net.corda.testing.driver.driver
import org.junit.ClassRule
import org.junit.Test
class BankOfCordaRPCClientTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(BOC.toDatabaseSchemaName(), DUMMY_NOTARY.toDatabaseSchemaName(),
BIGCORP_NAME.organisation)
}
@Test
fun `issuer flow via RPC`() {
val commonPermissions = setOf(

View File

@ -32,6 +32,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../testing/test-utils/src/main/resources')
}
}
}

View File

@ -28,6 +28,7 @@ import net.corda.testing.http.HttpApi
import net.corda.testing.node.NotarySpec
import org.apache.commons.io.IOUtils
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
import rx.Observable
import java.time.Duration
@ -36,12 +37,16 @@ import java.time.LocalDate
class IRSDemoTest : IntegrationTest() {
companion object {
private val log = contextLogger()
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
.map { it.toDatabaseSchemaName() }.toTypedArray())
}
private val rpcUsers = listOf(User("user", "password", setOf("ALL")))
private val currentDate: LocalDate = LocalDate.now()
private val futureDate: LocalDate = currentDate.plusMonths(6)
private val maxWaitTime: Duration = 60.seconds
private val maxWaitTime: Duration = 180.seconds
@Test
fun `runs IRS demo`() {

View File

@ -18,6 +18,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../testing/test-utils/src/main/resources')
}
}
}

View File

@ -3,9 +3,7 @@ package net.corda.vega
import com.opengamma.strata.product.common.BuySell
import net.corda.core.identity.CordaX500Name
import net.corda.core.utilities.getOrThrow
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.IntegrationTest
import net.corda.testing.*
import net.corda.testing.driver.driver
import net.corda.testing.http.HttpApi
import net.corda.vega.api.PortfolioApi
@ -13,6 +11,7 @@ import net.corda.vega.api.PortfolioApiUtils
import net.corda.vega.api.SwapDataModel
import net.corda.vega.api.SwapDataView
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
import java.math.BigDecimal
import java.time.LocalDate
@ -24,6 +23,10 @@ class SimmValuationTest : IntegrationTest() {
val nodeALegalName = DUMMY_BANK_A.name
val nodeBLegalName = DUMMY_BANK_B.name
val testTradeId = "trade1"
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(DUMMY_BANK_A, DUMMY_BANK_B, DUMMY_NOTARY)
.map { it.toDatabaseSchemaName() }.toTypedArray())
}
@Test

View File

@ -14,6 +14,9 @@ sourceSets {
runtimeClasspath += main.output + test.output
srcDir file('src/integration-test/kotlin')
}
resources {
srcDir file('../testing/test-utils/src/main/resources')
}
}
}

View File

@ -9,10 +9,7 @@ import net.corda.finance.flows.CashPaymentFlow
import net.corda.node.services.Permissions.Companion.all
import net.corda.node.services.Permissions.Companion.startFlow
import net.corda.nodeapi.User
import net.corda.testing.BOC
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_BANK_B
import net.corda.testing.chooseIdentity
import net.corda.testing.*
import net.corda.testing.driver.NodeHandle
import net.corda.testing.driver.driver
import net.corda.testing.driver.poll
@ -20,10 +17,16 @@ import net.corda.traderdemo.flow.BuyerFlow
import net.corda.traderdemo.flow.CommercialPaperIssueFlow
import net.corda.traderdemo.flow.SellerFlow
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
import java.util.concurrent.Executors
class TraderDemoTest {
class TraderDemoTest : IntegrationTest() {
companion object {
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(DUMMY_BANK_A, DUMMY_BANK_B, BOC, DUMMY_NOTARY)
.map { it.toDatabaseSchemaName() }.toTypedArray())
}
@Test
fun `runs trader demo`() {
val demoUser = User("demo", "demo", setOf(startFlow<SellerFlow>(), all()))

View File

@ -19,6 +19,7 @@ sourceSets {
}
resources {
srcDir file('src/integration-test/resources')
srcDir file('../testing/test-utils/src/main/resources')
}
}
}

View File

@ -6,13 +6,11 @@ import net.corda.core.internal.list
import net.corda.core.internal.readLines
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.NodeStartup
import net.corda.testing.DUMMY_BANK_A
import net.corda.testing.DUMMY_NOTARY
import net.corda.testing.DUMMY_REGULATOR
import net.corda.testing.*
import net.corda.testing.common.internal.ProjectStructure.projectRootDir
import net.corda.testing.IntegrationTest
import net.corda.testing.node.NotarySpec
import org.assertj.core.api.Assertions.assertThat
import org.junit.ClassRule
import org.junit.Test
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
@ -32,6 +30,10 @@ class DriverTests : IntegrationTest() {
// Check that the port is bound
addressMustNotBeBound(executorService, hostAndPort)
}
@ClassRule @JvmField
val databaseSchemas = IntegrationTestSchemas(*listOf(DUMMY_BANK_A, DUMMY_NOTARY, DUMMY_REGULATOR)
.map { it.toDatabaseSchemaName() }.toTypedArray())
}
@Test

View File

@ -20,6 +20,7 @@ import net.corda.core.serialization.SingletonSerializeAsToken
import net.corda.core.transactions.SignedTransaction
import net.corda.node.VersionInfo
import net.corda.node.internal.StateLoaderImpl
import net.corda.node.internal.configureDatabase
import net.corda.node.internal.cordapp.CordappLoader
import net.corda.node.services.api.SchemaService
import net.corda.node.services.api.StateMachineRecordedTransactionMappingStorage
@ -34,11 +35,17 @@ import net.corda.node.services.schema.HibernateObserver
import net.corda.node.services.schema.NodeSchemaService
import net.corda.node.services.transactions.InMemoryTransactionVerifierService
import net.corda.node.services.vault.NodeVaultService
import net.corda.node.internal.configureDatabase
import net.corda.nodeapi.internal.persistence.CordaPersistence
import net.corda.nodeapi.internal.persistence.DatabaseConfig
import net.corda.nodeapi.internal.persistence.HibernateConfiguration
import net.corda.nodeapi.internal.persistence.TransactionIsolationLevel
import net.corda.testing.*
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.database.DatabaseConstants.SCHEMA
import net.corda.testing.database.DatabaseConstants.TRANSACTION_ISOLATION_LEVEL
import org.bouncycastle.operator.ContentSigner
import rx.Observable
import rx.subjects.PublishSubject
@ -66,22 +73,37 @@ open class MockServices(
@JvmStatic
val MOCK_VERSION_INFO = VersionInfo(1, "Mock release", "Mock revision", "Mock Vendor")
private fun readDatabaseConfig(nodeName: String? = null, postifx: String? = null): Config {
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
private fun readDatabaseConfig(nodeName: String? = null, postfix: String? = null): Config {
val parseOptions = ConfigParseOptions.defaults()
//read overrides from command line (passed by Gradle as system properties)
val dataSourceKeys = listOf(DATA_SOURCE_URL, DATA_SOURCE_CLASSNAME, DATA_SOURCE_USER, DATA_SOURCE_PASSWORD)
val dataSourceSystemProperties = Properties()
val allSystemProperties = System.getProperties().toList().map { it.first.toString() to it.second.toString() }.toMap()
dataSourceKeys.filter { allSystemProperties.containsKey(it) }.forEach { dataSourceSystemProperties.setProperty(it, allSystemProperties[it]) }
val systemConfigOverride = ConfigFactory.parseProperties(dataSourceSystemProperties, parseOptions)
//read from db vendor specific configuration file
val databaseConfig = ConfigFactory.parseResources(System.getProperty("databaseProvider") + ".conf", parseOptions.setAllowMissing(true))
val fixedOverride = ConfigFactory.parseString("baseDirectory = \"\"")
val nodeOrganizationNameConfig = if (standarizedNodeName != null) configOf("nodeOrganizationName" to standarizedNodeName) else ConfigFactory.empty()
//implied property nodeOrganizationName to fill the potential placeholders in db schema/ db user properties
val standardizedNodeName = if (nodeName!= null) nodeName.replace(" ", "").replace("-", "_") else null
val nodeOrganizationNameConfig = if (standardizedNodeName != null) configOf("nodeOrganizationName" to standardizedNodeName) else ConfigFactory.empty()
//defaults to H2
//for 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 (postfix != null) standardizedNodeName + "_" + postfix else standardizedNodeName
val defaultProps = Properties()
defaultProps.setProperty("dataSourceProperties.dataSourceClassName", "org.h2.jdbcx.JdbcDataSource")
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.password", "")
defaultProps.setProperty(DATA_SOURCE_CLASSNAME, "org.h2.jdbcx.JdbcDataSource")
defaultProps.setProperty(DATA_SOURCE_URL, "jdbc:h2:mem:${h2InstanceName}_persistence;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE")
defaultProps.setProperty(DATA_SOURCE_USER, "sa")
defaultProps.setProperty(DATA_SOURCE_PASSWORD, "")
val defaultConfig = ConfigFactory.parseProperties(defaultProps, parseOptions)
return databaseConfig.withFallback(fixedOverride)
return systemConfigOverride.withFallback(databaseConfig)
.withFallback(fixedOverride)
.withFallback(nodeOrganizationNameConfig)
.withFallback(defaultConfig)
.resolve()
@ -112,7 +134,10 @@ open class MockServices(
@JvmStatic
fun makeTestDatabaseProperties(nodeName: String? = null): DatabaseConfig {
val config = readDatabaseConfig(nodeName)
return DatabaseConfig(schema = if (config.hasPath("database.schema")) config.getString("database.schema") else "")
val transactionIsolationLevel = if (config.hasPath(TRANSACTION_ISOLATION_LEVEL)) TransactionIsolationLevel.valueOf(config.getString(TRANSACTION_ISOLATION_LEVEL))
else TransactionIsolationLevel.READ_COMMITTED
val schema = if (config.hasPath(SCHEMA)) config.getString(SCHEMA) else ""
return DatabaseConfig(transactionIsolationLevel = transactionIsolationLevel, schema = schema)
}
private fun makeTestIdentityService() = InMemoryIdentityService(MOCK_IDENTITIES, trustRoot = DEV_TRUST_ROOT)
@ -144,9 +169,9 @@ open class MockServices(
cordappPackages: List<String> = emptyList(),
initialIdentityName: CordaX500Name): Pair<CordaPersistence, MockServices> {
val cordappLoader = CordappLoader.createWithTestPackages(cordappPackages)
val dataSourceProps = makeTestDataSourceProperties()
val dataSourceProps = makeTestDataSourceProperties(initialIdentityName.organisation)
val schemaService = NodeSchemaService(cordappLoader.cordappSchemas)
val database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(), identityService, schemaService)
val database = configureDatabase(dataSourceProps, makeTestDatabaseProperties(initialIdentityName.organisation), identityService, schemaService)
val mockService = database.transaction {
object : MockServices(cordappLoader, initialIdentityName = initialIdentityName, keys = *(keys.toTypedArray())) {
override val identityService get() = identityService

View File

@ -1,10 +1,12 @@
package net.corda.testing
import net.corda.core.identity.Party
import net.corda.testing.database.DbScriptRunner.runDbScript
import org.junit.After
import org.junit.AfterClass
import org.junit.Before
import org.junit.BeforeClass
import org.junit.rules.ExternalResource
/**
* Base class for all integration tests that require common setup and/or teardown.
@ -12,6 +14,8 @@ import org.junit.BeforeClass
*/
abstract class IntegrationTest {
open protected val databaseSchemas = Companion.databaseSchemas
// System properties set in main 'corda-project' build.gradle
// Note: the database provider configuration file for integration tests should specify:
// dataSource.user = ${nodeOrganizationName}
@ -22,19 +26,20 @@ abstract class IntegrationTest {
private val dbProvider = System.getProperty(DATABASE_PROVIDER, "")
private val TEST_DB_SCRIPT_DIR = "test.db.script.dir"
private val testDbScriptDir = System.getProperty(TEST_DB_SCRIPT_DIR, "database-scripts")
var databaseSchemas = mutableListOf<String>()
@BeforeClass
@JvmStatic
fun globalSetUp() {
if (dbProvider.isNotEmpty()) {
runDbScript(dbProvider,"$testDbScriptDir/db-global-setup-${this::class.simpleName}.sql")
runDbScript(dbProvider,"$testDbScriptDir/db-global-setup.sql", databaseSchemas)
}
}
@AfterClass
@JvmStatic
fun globalTearDown() {
if (dbProvider.isNotEmpty()) {
runDbScript(dbProvider,"$testDbScriptDir/db-global-cleanup-${this::class.simpleName}.sql")
runDbScript(dbProvider,"$testDbScriptDir/db-global-cleanup.sql", databaseSchemas)
}
}
}
@ -43,15 +48,31 @@ abstract class IntegrationTest {
@Throws(Exception::class)
open fun setUp() {
if (dbProvider.isNotEmpty()) {
runDbScript(dbProvider,"$testDbScriptDir/db-setup-${this::class.simpleName}.sql")
runDbScript(dbProvider,"$testDbScriptDir/db-setup.sql", databaseSchemas)
}
}
@After
open fun tearDown() {
if (dbProvider.isNotEmpty()) {
runDbScript(dbProvider,"$testDbScriptDir/db-cleanup-${this::class.simpleName}.sql")
runDbScript(dbProvider,"$testDbScriptDir/db-cleanup.sql", databaseSchemas)
}
}
}
class IntegrationTestSchemas(vararg var list : String) : ExternalResource() {
override fun before() {
IntegrationTest.Companion.databaseSchemas.addAll(list)
}
override fun after() {
IntegrationTest.Companion.databaseSchemas.clear()
}
}
fun Party.toDatabaseSchemaName() = this.name.organisation.replace(" ", "").replace("-", "_")
fun Party.toDatabaseSchemaNames(vararg postfixes: String): List<String> {
val nodeName = this.toDatabaseSchemaName()
return postfixes.map { "$nodeName$it" }
}

View File

@ -0,0 +1,10 @@
package net.corda.testing.database
object DatabaseConstants {
const val DATA_SOURCE_URL = "dataSourceProperties.dataSource.url"
const val DATA_SOURCE_CLASSNAME = "dataSourceProperties.dataSourceClassName"
const val DATA_SOURCE_USER = "dataSourceProperties.dataSource.user"
const val DATA_SOURCE_PASSWORD = "dataSourceProperties.dataSource.password"
const val TRANSACTION_ISOLATION_LEVEL = "database.transactionIsolationLevel"
const val SCHEMA = "database.schema"
}

View File

@ -3,10 +3,20 @@ package net.corda.testing.database
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigParseOptions
import net.corda.core.utilities.loggerFor
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 org.apache.commons.logging.LogFactory
import org.springframework.core.io.ClassPathResource
import org.springframework.core.io.support.EncodedResource
import org.springframework.jdbc.datasource.DriverManagerDataSource
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
import org.springframework.jdbc.datasource.init.*
import org.springframework.util.StringUtils
import java.sql.Connection
import java.sql.SQLException
import java.sql.SQLWarning
import java.util.*
object DbScriptRunner {
private val log = loggerFor<DbScriptRunner>()
@ -15,19 +25,106 @@ object DbScriptRunner {
private const val TEST_DB_ADMIN_USER = "test.db.admin.user"
private const val TEST_DB_ADMIN_PASSWORD = "test.db.admin.password"
fun runDbScript(dbProvider: String, initScript: String) {
private fun createDataSource(dbProvider: String) : DriverManagerDataSource {
val parseOptions = ConfigParseOptions.defaults()
val databaseConfig = ConfigFactory.parseResources("$dbProvider.conf", parseOptions.setAllowMissing(false))
val allSystemProperties = System.getProperties().toList().map { it.first.toString() to it.second.toString() }.toMap()
val dataSourceSystemProperties = Properties()
val dataSourceKeys = listOf(TEST_DB_ADMIN_USER, TEST_DB_ADMIN_PASSWORD, DATA_SOURCE_URL, DATA_SOURCE_CLASSNAME,
DATA_SOURCE_USER, DATA_SOURCE_PASSWORD)
dataSourceKeys.filter { allSystemProperties.containsKey(it) }.forEach { dataSourceSystemProperties.setProperty(it, allSystemProperties[it]) }
val databaseConfig = ConfigFactory.parseProperties(dataSourceSystemProperties, parseOptions)
.withFallback(ConfigFactory.parseResources("$dbProvider.conf", parseOptions.setAllowMissing(false)))
val dataSource = DriverManagerDataSource()
dataSource.setDriverClassName(databaseConfig.getString("dataSourceProperties.dataSourceClassName"))
dataSource.url = databaseConfig.getString("dataSourceProperties.dataSource.url")
dataSource.username = System.getProperty(TEST_DB_ADMIN_USER)
dataSource.password = System.getProperty(TEST_DB_ADMIN_PASSWORD)
val initSchema = ClassPathResource(initScript )
if (initSchema.exists()) {
val databasePopulator = ResourceDatabasePopulator(false, true, null, initSchema)
DatabasePopulatorUtils.execute(databasePopulator, dataSource)
dataSource.setDriverClassName(databaseConfig.getString(DATA_SOURCE_CLASSNAME))
dataSource.url = databaseConfig.getString(DATA_SOURCE_URL)
dataSource.username = databaseConfig.getString(TEST_DB_ADMIN_USER)
dataSource.password = databaseConfig.getString(TEST_DB_ADMIN_PASSWORD)
return dataSource
}
fun runDbScript(dbProvider: String, initScript: String? = null, databaseSchemas: List<String> = emptyList()) {
if (initScript != null) {
val initSchema = ClassPathResource(initScript)
if (initSchema.exists()) {
val encodedResource = EncodedResource(initSchema)
val inputString = encodedResource.inputStream.bufferedReader().use { it.readText().split("\n") }
val resolvedScripts = merge(inputString, databaseSchemas)
log.info("Executing DB Script for schemas $databaseSchemas with ${resolvedScripts.size} statements.")
DatabasePopulatorUtils.execute(ListPopulator(false, true, resolvedScripts),
createDataSource(dbProvider))
} else log.warn("DB Script missing: $initSchema")
}
}
fun merge(scripts: List<String>, schema: String): List<String> =
scripts.map { it.replace("\${schema}", schema) }
fun merge(scripts: List<String>, schemas: List<String>): List<String> =
if(schemas.isEmpty()) scripts else schemas.map { merge(scripts, it) }.flatten()
}
//rewritten version of org.springframework.jdbc.datasource.init.ResourceDatabasePopulator
class ListPopulator(private val continueOnError: Boolean,
private val ignoreFailedDrops: Boolean,
private val statements: List<String>) : DatabasePopulator {
private val logger = LogFactory.getLog(ScriptUtils::class.java)
override fun populate(connection: Connection) {
try {
if (logger.isInfoEnabled) {
logger.info("Executing SQL script " )
}
val startTime = System.currentTimeMillis()
val resource = statements.toString().substring(0,30) + " [...]"
var stmtNumber = 0
val stmt = connection.createStatement()
try {
for (statement in statements) {
stmtNumber++
try {
stmt.execute(statement)
val rowsAffected = stmt.updateCount
if (logger.isDebugEnabled) {
logger.debug(rowsAffected.toString() + " returned as update count for SQL: " + statement)
var warningToLog: SQLWarning? = stmt.warnings
while (warningToLog != null) {
logger.debug("SQLWarning ignored: SQL state '" + warningToLog.sqlState +
"', error code '" + warningToLog.errorCode +
"', message [" + warningToLog.message + "]")
warningToLog = warningToLog.nextWarning
}
}
} catch (ex: SQLException) {
val dropStatement = StringUtils.startsWithIgnoreCase(statement.trim { it <= ' ' }, "drop")
if (continueOnError || dropStatement && ignoreFailedDrops) {
if (logger.isDebugEnabled) {
logger.debug(ex)
}
} else {
throw ex
}
}
}
} finally {
try {
stmt.close()
} catch (ex: Throwable) {
logger.debug("Could not close JDBC Statement", ex)
}
}
val elapsedTime = System.currentTimeMillis() - startTime
if (logger.isInfoEnabled) {
logger.info("Executed SQL script from $resource in $elapsedTime ms.")
}
logger.info("Executed SQL script $resource" )
} catch (ex: Exception) {
if (ex is ScriptException) {
throw ex
}
throw UncategorizedScriptException(
"Failed to execute database script from resource [resource]", ex)
}
else log.warn("DB Script missing: $initSchema")
}
}

View File

@ -0,0 +1,49 @@
DROP TABLE IF EXISTS ${schema}.node_attachments;
DROP TABLE IF EXISTS ${schema}.node_checkpoints;
DROP TABLE IF EXISTS ${schema}.node_transactions;
DROP TABLE IF EXISTS ${schema}.node_message_retry;
DROP TABLE IF EXISTS ${schema}.node_message_ids;
DROP TABLE IF EXISTS ${schema}.vault_states;
DROP TABLE IF EXISTS ${schema}.node_our_key_pairs;
DROP TABLE IF EXISTS ${schema}.node_scheduled_states;
DROP TABLE IF EXISTS ${schema}.node_network_map_nodes;
DROP TABLE IF EXISTS ${schema}.node_network_map_subscribers;
DROP TABLE IF EXISTS ${schema}.node_notary_commit_log;
DROP TABLE IF EXISTS ${schema}.node_transaction_mappings;
DROP TABLE IF EXISTS ${schema}.vault_fungible_states_parts;
DROP TABLE IF EXISTS ${schema}.vault_linear_states_parts;
DROP TABLE IF EXISTS ${schema}.vault_fungible_states;
DROP TABLE IF EXISTS ${schema}.vault_linear_states;
DROP TABLE IF EXISTS ${schema}.node_bft_committed_states;
DROP TABLE IF EXISTS ${schema}.node_raft_committed_states;
DROP TABLE IF EXISTS ${schema}.vault_transaction_notes;
DROP TABLE IF EXISTS ${schema}.link_nodeinfo_party;
DROP TABLE IF EXISTS ${schema}.node_link_nodeinfo_party;
DROP TABLE IF EXISTS ${schema}.node_info_party_cert;
DROP TABLE IF EXISTS ${schema}.node_info_hosts;
DROP TABLE IF EXISTS ${schema}.node_infos;
DROP TABLE IF EXISTS ${schema}.cp_states;
DROP TABLE IF EXISTS ${schema}.node_contract_upgrades;
DROP TABLE IF EXISTS ${schema}.node_identities;
DROP TABLE IF EXISTS ${schema}.node_named_identities;
DROP TABLE IF EXISTS ${schema}.children;
DROP TABLE IF EXISTS ${schema}.parents;
DROP TABLE IF EXISTS ${schema}.contract_cash_states;
DROP TABLE IF EXISTS ${schema}.messages;
DROP TABLE IF EXISTS ${schema}.DummyDealStateSchemaV1$PersistentDummyDealState_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV1$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.DummyLinearStateSchemaV2$PersistentDummyLinearState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV2$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCashSchemaV3$PersistentCashState_participants;
DROP TABLE IF EXISTS ${schema}.SampleCommercialPaperSchemaV2$PersistentCommercialPaperState_participants;
DROP TABLE IF EXISTS ${schema}.cash_states_v2;
DROP TABLE IF EXISTS ${schema}.cash_states_v3;
DROP TABLE IF EXISTS ${schema}.cp_states_v2;
DROP TABLE IF EXISTS ${schema}.dummy_deal_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states;
DROP TABLE IF EXISTS ${schema}.dummy_linear_states_v2;
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};
GRANT ALTER, DELETE, EXECUTE, INSERT, REFERENCES, SELECT, UPDATE, VIEW DEFINITION ON SCHEMA::${schema} TO ${schema};
GRANT CREATE TABLE, CREATE PROCEDURE, CREATE FUNCTION, CREATE VIEW TO ${schema};

View File

@ -0,0 +1,87 @@
--once off script to run against master database (not a user database)
CREATE LOGIN AliceCorp WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER AliceCorp FROM LOGIN AliceCorp;
CREATE LOGIN AliceCorp_10000 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER AliceCorp_10000 FROM LOGIN AliceCorp_10003;
CREATE LOGIN AliceCorp_10003 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER AliceCorp_10003 FROM LOGIN AliceCorp_10003;
CREATE LOGIN AliceCorp_10006 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER AliceCorp_10006 FROM LOGIN AliceCorp_10006;
CREATE LOGIN BankA WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BankA FROM LOGIN BankA;
CREATE LOGIN BankA_10000 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BankA_10000 FROM LOGIN BankA_10000;
CREATE LOGIN BankA_10003 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BankA_10003 FROM LOGIN BankA_10003;
CREATE LOGIN BankA_10006 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BankA_10006 FROM LOGIN BankA_10006;
CREATE LOGIN BankB WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BankB FROM LOGIN BankB;
CREATE LOGIN BobPlc WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BobPlc FROM LOGIN BobPlc;
CREATE LOGIN BobPlc_10000 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BobPlc_10000 FROM LOGIN BobPlc_10000;
CREATE LOGIN BobPlc_10003 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BobPlc_10003 FROM LOGIN BobPlc_10003;
CREATE LOGIN BobPlc_10006 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BobPlc_10006 FROM LOGIN BobPlc_10006;
CREATE LOGIN CharlieLtd WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER CharlieLtd FROM LOGIN CharlieLtd;
CREATE LOGIN DistributedService_0 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER DistributedService_0 FROM LOGIN DistributedService_0;
CREATE LOGIN DistributedService_1 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER DistributedService_1 FROM LOGIN DistributedService_1;
CREATE LOGIN NetworkMapService WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NetworkMapService FROM LOGIN NetworkMapService;
CREATE LOGIN Notary WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER Notary FROM LOGIN Notary;
CREATE LOGIN NotaryService WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NotaryService FROM LOGIN NotaryService;
CREATE LOGIN NotaryService0 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NotaryService0 FROM LOGIN NotaryService0;
CREATE LOGIN NotaryService1 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NotaryService1 FROM LOGIN NotaryService1;
CREATE LOGIN NotaryService2 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NotaryService2 FROM LOGIN NotaryService2;
CREATE LOGIN NotaryService_0 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NotaryService_0 FROM LOGIN NotaryService_0;
CREATE LOGIN NotaryService_1 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NotaryService_1 FROM LOGIN NotaryService_1;
CREATE LOGIN NotaryService_2 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER NotaryService_2 FROM LOGIN NotaryService_2;
CREATE LOGIN MegaCorp WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER MegaCorp FOR LOGIN MegaCorp;
CREATE LOGIN node_0 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_0 FOR LOGIN node_0;
CREATE LOGIN node_1 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_1 FOR LOGIN node_1;
CREATE LOGIN node_2 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_2 FOR LOGIN node_2;
CREATE LOGIN node_3 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_3 FOR LOGIN node_3;
CREATE LOGIN node_4 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_4 FOR LOGIN node_4;
CREATE LOGIN node_5 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_5 FOR LOGIN node_5;
CREATE LOGIN node_6 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_6 FOR LOGIN node_6;
CREATE LOGIN node_7 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_7 FOR LOGIN node_7;
CREATE LOGIN node_8 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_8 FOR LOGIN node_8;
CREATE LOGIN node_9 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER node_9 FOR LOGIN node_9;
CREATE LOGIN RAFTNotaryService_0 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER RAFTNotaryService_0 FROM LOGIN RAFTNotaryService_0;
CREATE LOGIN RAFTNotaryService_1 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER RAFTNotaryService_1 FROM LOGIN RAFTNotaryService_1;
CREATE LOGIN RAFTNotaryService_2 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER RAFTNotaryService_2 FROM LOGIN RAFTNotaryService_2;
CREATE LOGIN RegulatorA WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER RegulatorA FROM LOGIN RegulatorA;
CREATE LOGIN AliceCorp_10012 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER AliceCorp_10012 FROM LOGIN AliceCorp_10012;
CREATE LOGIN BobPlc_10012 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BobPlc_10012 FROM LOGIN BobPlc_10012;
CREATE LOGIN BankA_10012 WITH PASSWORD = 'yourStrong(!)Password';
CREATE USER BankA_10012 FROM LOGIN BankA_10012;

View File

@ -0,0 +1,11 @@
dataSourceProperties = {
dataSourceClassName = "com.microsoft.sqlserver.jdbc.SQLServerDataSource"
dataSource.url = "jdbc:sqlserver://[HOST]:1433;databaseName=[DATABASE];encrypt=true;trustServerCertificate=false;hostNameInCertificate=*.database.windows.net;loginTimeout=30"
dataSource.user = ${nodeOrganizationName}
dataSource.password = "yourStrong(!)Password"
}
database = {
transactionIsolationLevel = READ_COMMITTED
initDatabase = true
schema = ${nodeOrganizationName}
}

View File

@ -0,0 +1,11 @@
dataSourceProperties = {
dataSourceClassName = "com.microsoft.sqlserver.jdbc.SQLServerDataSource"
dataSource.url = "jdbc:sqlserver://[HOST]:[PORT]"
dataSource.user = ${nodeOrganizationName}
dataSource.password = "yourStrong(!)Password"
}
database = {
transactionIsolationLevel = READ_COMMITTED
initDatabase = true
schema = ${nodeOrganizationName}
}