ENT-1424 - Setup Compatibility testing environment (#1211)

* Updated interoperability scenarios to use GA Release Candidate

* Removed "with proxy" and updated incorrect reference to OS master.

* Update to resolve Artifactory tools if available (blob-inspector, network-bootstrapper, database-migration)

* Allow passing in of argument to specify one or more scenarios to run.

* Updated to RC03.

* Added Oracle support in Behave framework and included functional test scenarios.

* behave test using snapshot (#970)

* make behave use snapshots from artifactory

* rebase and fix

* address PR issues

* address PR issues

* gradle task for bdd (#989)

* gradle task for bdd (#989)

* fix typo

* Publishing behave-api jar for use by external applications (eg. cordapp-option).
Fixed SIMMM valuation behave scenario test and startup.

* Publishing behave-api jar for use by external applications (eg. cordapp-option).
Fixed SIMMM valuation behave scenario test and startup.

* Various fixes to make BDD working in Teamcity (#1063)

* fix typo

* print docker log

* print docker log

* attempt to fix docker

* attempt to fix docker

* attempt to fix docker

* update to RC04

* disable clean up

* try to find out why the test pick up the wrong jar

* test

* minor fixes

* fix wrong bootstrapping procedure

* remove DISABLE_CLEANUP

* attempt to fix error

* fixes to get postgres working

* enable cleanup

* generate cucumber report

* bump to RC06

* attempt to make cucumber generate http report

* cucumber report

* some minor cleanup

* removed DP3 nodes from scenarios, added oracle and bumped to RC07

* fix licence issue

* fixed bootstrapper placing corda jar

* Update interoperability.feature

* Added missing published artifact.

* Fixed compilation errors raised by stricter compilation flag checking.

* Minor changes following rebase from master and re-testing.

* Updates to reflect last minute naming and versioning changes applied to 3.0 release.
Updated scenarios to use the officially released version of CE 3.0

* Updates following lastest PR review feedback.

* Updates following lastest PR review feedback.

* Align with master (maxMessageSize = mazTransactionSize).

* Fix snapshot version regex matching.

* Set logging level to DEBUG to ensure pattern matches catch log message output which has been downgraded from INFO

* Add all supported interoperable versions.
This commit is contained in:
josecoll 2018-07-31 17:53:24 +01:00 committed by GitHub
parent 52c1ed274d
commit 4db315f81a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 596 additions and 178 deletions

View File

@ -403,6 +403,7 @@ bintrayConfig {
'jmeter-corda',
'tools-database-manager',
'corda-installer',
'corda-behave-api',
'corda-notary-healthcheck-contract',
'corda-notary-healthcheck-cordapp',
'corda-notary-healthcheck-client'

View File

@ -19,6 +19,7 @@ group 'net.corda.behave'
apply plugin: 'kotlin'
apply plugin: 'net.corda.plugins.publish-utils'
apply plugin: 'com.jfrog.artifactory'
sourceSets {
behave {
@ -113,6 +114,7 @@ task smokeTest(type: Test) {
}
task behaveJar(type: Jar) {
group = "behave"
baseName "corda-behave"
from sourceSets.behave.output
from {
@ -131,8 +133,28 @@ task behaveJar(type: Jar) {
}
}
task prepareBehave(type: Exec, dependsOn: behaveJar) {
group = "behave"
environment "STAGING_ROOT", "${workingDir}/build/libs"
commandLine './prepare.sh'
}
task runBehaveScenario(type: JavaExec) {
group = "behave"
systemProperty "STAGING_ROOT", "${workingDir}/build/libs"
main = "-jar";
args = [
behaveJar.archivePath,
"-path",
"${rootDir}/${System.getenv("BDD_SCENARIO_PATH") ?: "testing/qa/behave/compatibility/resources/features/version.feature"}",
"-plugin",
"html:build/runs/cucumberReport"
]
}
task apiJar(type: Jar, dependsOn: classes) {
baseName "corda-behave-api"
archiveName = "corda-behave-api-${version}.jar"
from sourceSets.behave.output
from {
configurations.behaveCompile.collect {
@ -146,10 +168,20 @@ task apiJar(type: Jar, dependsOn: classes) {
include 'io/github/lukehutch/**'
exclude '**/features/**'
exclude '**/scripts/**'
exclude '**/resources/doorman/**'
}
jar {
classifier "ignore"
}
publish {
name 'corda-behave-api'
disableDefaultJar = true
}
artifacts {
testArtifacts apiJar
}
jar.finalizedBy (apiJar, behaveJar)
jar.finalizedBy(apiJar, behaveJar)

View File

@ -48,6 +48,9 @@ cp -v $(ls samples/simm-valuation-demo/flows/build/libs/flows-*.jar | tail -n1)
curl "https://search.maven.org/remotecontent?filepath=com/h2database/h2/1.4.196/h2-1.4.196.jar" > ${DRIVERS_DIR}/h2-1.4.196.jar
curl -L "http://central.maven.org/maven2/org/postgresql/postgresql/42.1.4/postgresql-42.1.4.jar" > ${DRIVERS_DIR}/postgresql-42.1.4.jar
curl -L "https://github.com/Microsoft/mssql-jdbc/releases/download/v6.2.2/mssql-jdbc-6.2.2.jre8.jar" > ${DRIVERS_DIR}/mssql-jdbc-6.2.2.jre8.jar
curl -L "http://www.datanucleus.org/downloads/maven2/oracle/ojdbc6/11.2.0.3/ojdbc6-11.2.0.3.jar" > ${DRIVERS_DIR}/ojdbc6.jar
# The following download requires an account authenticated against the Oracle Technology Network.
#curl -L "http://download.oracle.com/otn/utilities_drivers/jdbc/122010/ojdbc8.jar" > ${DRIVERS_DIR}/ojdbc8.jar
# Build Network Bootstrapper
./gradlew tools:bootstrapper:jar
@ -60,7 +63,7 @@ cp -v $(ls tools/bootstrapper/build/libs/*.jar | tail -n1) ${CORDA_DIR}/network-
# build and distribute DB Migration tool
./gradlew tools:dbmigration:shadowJar
cp -v $(ls tools/dbmigration/build/libs/*migration-*.jar | tail -n1) ${CORDA_DIR}/dbmigration.jar
cp -v $(ls tools/dbmigration/build/libs/database-manager-*.jar | tail -n1) ${CORDA_DIR}/database-manager.jar
# Build rpcProxy (required by CTS Scenario Driver to call Corda 3.0 which continues to use Kryo for RPC)
./gradlew testing:qa:behave:tools:rpc-proxy:rpcProxyJar

View File

@ -11,12 +11,12 @@
package net.corda.behave.database
import net.corda.behave.database.configuration.H2ConfigurationTemplate
import net.corda.behave.database.configuration.OracleConfigurationTemplate
import net.corda.behave.database.configuration.PostgresConfigurationTemplate
import net.corda.behave.database.configuration.SqlServerConfigurationTemplate
import net.corda.behave.node.configuration.Configuration
import net.corda.behave.node.configuration.DatabaseConfiguration
import net.corda.behave.service.database.H2Service
import net.corda.behave.service.database.PostgreSQLService
import net.corda.behave.service.database.*
enum class DatabaseType(val settings: DatabaseSettings) {
@ -37,11 +37,12 @@ enum class DatabaseType(val settings: DatabaseSettings) {
.withUser(SqlServerService.username)
.withConfigTemplate(SqlServerConfigurationTemplate())
.withServiceInitiator {
PostgreSQLService("postgres-${it.name}", it.database.port, it.database.password)
SqlServerService("sql-server-${it.name}", it.database.port, it.database.password)
}
),
POSTGRES(DatabaseSettings()
.withDatabase(PostgreSQLService.database)
.withDriver(PostgreSQLService.driver)
.withSchema(PostgreSQLService.schema)
.withUser(PostgreSQLService.username)
@ -49,6 +50,26 @@ enum class DatabaseType(val settings: DatabaseSettings) {
.withServiceInitiator {
PostgreSQLService("postgres-${it.name}", it.database.port, it.database.password)
}
),
ORACLE_12C(DatabaseSettings()
.withDriver(Oracle12cService.driver)
.withSchema(OracleService.schema)
.withUser(OracleService.username)
.withConfigTemplate(OracleConfigurationTemplate())
.withServiceInitiator {
Oracle12cService("oracle-12c-${it.name}", it.database.port, it.database.password)
}
),
ORACLE_11G(DatabaseSettings()
.withDriver(Oracle11gService.driver)
.withSchema(OracleService.schema)
.withUser(OracleService.username)
.withConfigTemplate(OracleConfigurationTemplate())
.withServiceInitiator {
Oracle11gService("oracle-11g-${it.name}", it.database.port, it.database.password)
}
);
val driverJar = settings.driverJar
@ -64,6 +85,10 @@ enum class DatabaseType(val settings: DatabaseSettings) {
"sqlserver" -> SQL_SERVER
"postgres" -> POSTGRES
"postgresql" -> POSTGRES
"oracle11" -> ORACLE_11G
"oracle11g" -> ORACLE_11G
"oracle12" -> ORACLE_12C
"oracle12c" -> ORACLE_12C
else -> null
}
}

View File

@ -0,0 +1,37 @@
/*
* R3 Proprietary and Confidential
*
* Copyright (c) 2018 R3 Limited. All rights reserved.
*
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
*
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.behave.database.configuration
import net.corda.behave.database.DatabaseConfigurationTemplate
import net.corda.behave.node.configuration.DatabaseConfiguration
class OracleConfigurationTemplate : DatabaseConfigurationTemplate() {
override val connectionString: (DatabaseConfiguration) -> String
get() = { "jdbc:oracle:thin:@${it.host}:${it.port}:xe" }
override val config: (DatabaseConfiguration) -> String
get() = {
"""
|dataSourceProperties = {
| dataSourceClassName = "oracle.jdbc.pool.OracleDataSource"
| dataSource.url = "${connectionString(it)}"
| dataSource.user = "${it.username}"
| dataSource.password = "${it.password}"
|}
|database = {
| runMigration=true
| transactionIsolationLevel = READ_COMMITTED
| schema="${it.schema}"
|}
"""
}
}

View File

@ -28,7 +28,9 @@ class PostgresConfigurationTemplate : DatabaseConfigurationTemplate() {
| dataSource.password = "${it.password}"
|}
|database = {
| runMigration=true
| transactionIsolationLevel = READ_COMMITTED
| schema="${it.schema}"
|}
"""
}

View File

@ -92,8 +92,7 @@ class Network private constructor(
}
fun addNode(nodeBuilder: Node.Builder): Builder {
nodeBuilder
.withDirectory(directory)
nodeBuilder.withDirectory(directory)
.withTimeout(timeout)
val node = nodeBuilder.build()
nodes[node.config.name] = node
@ -103,26 +102,19 @@ class Network private constructor(
fun generate(): Network {
val network = Network(nodes, directory, timeout)
network.copyDatabaseDrivers()
if (!network.configureNodes()) {
throw CordaException("Unable to configure nodes in Corda network. Please check logs in $directory")
}
if (networkType == Distribution.Type.CORDA_ENTERPRISE && System.getProperty("USE_NETWORK_SERVICES") != null)
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
network.bootstrapDoorman()
else
network.bootstrapLocalNetwork(networkType)
network.bootstrapLocalNetwork()
return network
}
}
fun copyDatabaseDrivers() {
val driverDirectory = (targetDirectory / "libs").createDirectories()
log.info("Copying database drivers from $stagingRoot/drivers to $driverDirectory")
Files.copy((stagingRoot / "drivers"), driverDirectory, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING)
}
fun configureNodes(): Boolean {
var allDependenciesStarted = true
log.info("Configuring nodes ...")
@ -160,6 +152,7 @@ class Network private constructor(
}
log.info("Running command: {}", command)
command.output.subscribe {
log.info(it)
if (it.contains("Exception")) {
log.warn("Found error in output; interrupting command execution ...\n{}", it)
command.interrupt()
@ -184,13 +177,9 @@ class Network private constructor(
return command
}
private fun bootstrapLocalNetwork(networkType: Distribution.Type) {
// Use master version of Bootstrapper
val bootstrapper =
when (networkType) {
Distribution.Type.CORDA_OS -> Distribution.MASTER.networkBootstrapper
Distribution.Type.CORDA_ENTERPRISE -> Distribution.R3_MASTER.networkBootstrapper
}
private fun bootstrapLocalNetwork() {
// Use master version of Bootstrapper, it doesn't matter which bootstrapper we use because we provide corda.jar, the bootstrapper will use the provided jar found in the base dir.
val bootstrapper = Distribution.R3_MASTER.networkBootstrapper
log.info("Bootstrapper URL: $bootstrapper\n")
if (!bootstrapper.exists()) {
@ -201,7 +190,7 @@ class Network private constructor(
log.info("Bootstrapping network, please wait ...")
val command = JarCommand(
bootstrapper,
arrayOf("$targetDirectory"),
arrayOf("--dir=$targetDirectory"),
targetDirectory,
timeout
)
@ -221,8 +210,7 @@ class Network private constructor(
timeout
)
runCommand(rpcProxyCommand)
}
else {
} else {
log.warn("Missing RPC proxy startup script ($startProxyScript). Continuing ...")
}
}
@ -236,9 +224,9 @@ class Network private constructor(
log.info("Deleting temporary files, but retaining logs and config ...")
for (node in nodes.values) {
val nodeDir = targetDirectory / node.config.name
nodeDir.list { paths -> paths
.filter { it.fileName.toString() !in setOf("logs", "node.conf") }
.forEach(Path::deleteRecursively)
nodeDir.list { paths ->
paths.filter { it.fileName.toString() !in setOf("logs", "node.conf") }
.forEach(Path::deleteRecursively)
}
}
listOf("libs", ".cache").forEach { (targetDirectory / it).deleteRecursively() }
@ -340,8 +328,7 @@ class Network private constructor(
// TODO: consider generic implementation to support non *nix platforms
Command(listOf("kill", "-9", pid)).run()
(tmpDirectory / "rpcProxy-pid-$rpcProxyPortNo").deleteIfExists()
}
catch (e: Exception) {
} catch (e: Exception) {
log.warn("Unable to locate PID file: ${e.message}")
}
}

View File

@ -48,7 +48,7 @@ class Distribution private constructor(
/**
* Map of all distribution JAR artifacts from artifactory, if available.
*/
val artifactUrlMap: Map<String,URL>? = null,
val artifactUrlMap: Map<String, URL>? = null,
/**
* The Docker image details, if available
@ -84,7 +84,7 @@ class Distribution private constructor(
/**
* The path to the DB migration jar (Corda Enterprise only).
*/
val dbMigrationJar: Path = nodePrefix / version / "dbmigration.jar"
val dbMigrationJar: Path = nodePrefix / version / "database-manager.jar"
/**
* Ensure that the distribution is available on disk.
@ -103,12 +103,11 @@ class Distribution private constructor(
artifactUrl.openStream().use {
if (artifactName.startsWith("corda-finance")) {
it.copyTo(cordappDirectory / "$artifactName.jar", StandardCopyOption.REPLACE_EXISTING)
}
else it.copyTo(path / "$artifactName.jar", StandardCopyOption.REPLACE_EXISTING)
} else it.copyTo(path / "$artifactName.jar", StandardCopyOption.REPLACE_EXISTING)
}
}
} catch (e: Exception) {
if ("HTTP response code: 401" in e.message!!) {
if (e.message?.contains("HTTP response code: 401") == true) {
log.warn("CORDA_ARTIFACTORY_USERNAME ${System.getenv("CORDA_ARTIFACTORY_USERNAME")}")
log.warn("CORDA_ARTIFACTORY_PASSWORD ${System.getenv("CORDA_ARTIFACTORY_PASSWORD")}")
throw Exception("Incorrect Artifactory permission. Please set CORDA_ARTIFACTORY_USERNAME and CORDA_ARTIFACTORY_PASSWORD environment variables correctly.")
@ -122,14 +121,17 @@ class Distribution private constructor(
*/
override fun toString() = "Corda(version = $version, path = $cordaJar)"
enum class Type(val artifacts: Set<String>) {
CORDA_OS(setOf("corda", "corda-webserver", "corda-finance")),
enum class Type(val groupId: String, val repositoryId: String, val artifacts: Set<String>, val requireAuthentication: Boolean = false) {
CORDA_OS("net.corda", "corda-releases", setOf("corda", "corda-webserver", "corda-finance")),
CORDA_OS_SNAPSHOT("net.corda", "corda-dev", setOf("corda", "corda-webserver", "corda-finance")),
// bridge-server not available in Enterprise Dev Previews
// migration-tool not published in Enterprise Dev Previews
CORDA_ENTERPRISE(setOf("corda", "corda-webserver", "corda-finance", "corda-firewall", "migration-tool"))
CORDA_ENTERPRISE("com.r3.corda", "r3-corda-releases", setOf("corda", "corda-webserver", "corda-finance", "corda-tools-database-manager"), requireAuthentication = true),
CORDA_ENTERPRISE_SNAPSHOT("com.r3.corda", "r3-corda-dev", setOf("corda", "corda-webserver", "corda-finance", "tools-database-manager"), requireAuthentication = true)
}
companion object {
private const val ARTIFACTORY_URL = "https://ci-artifactory.corda.r3cev.com/artifactory"
private val log = contextLogger()
@ -146,32 +148,23 @@ class Distribution private constructor(
* @param version The version of the Corda distribution.
*/
fun fromArtifactory(type: Type, version: String): Distribution {
val artifactUrlMap = when (type) {
Type.CORDA_OS -> resolveArtifacts(Type.CORDA_OS.artifacts, version, "https://ci-artifactory.corda.r3cev.com/artifactory/corda-releases/net/corda")
Type.CORDA_ENTERPRISE -> {
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(System.getenv("CORDA_ARTIFACTORY_USERNAME"), System.getenv("CORDA_ARTIFACTORY_PASSWORD").toCharArray())
}
})
resolveArtifacts(Type.CORDA_ENTERPRISE.artifacts, version, "https://ci-artifactory.corda.r3cev.com/artifactory/r3-corda-releases/com/r3/corda")
}
}
val artifactUrlMap = resolveArtifacts(type, version)
val distribution = Distribution(type, version, artifactUrlMap = artifactUrlMap)
distributions.add(distribution)
return distribution
}
private fun resolveArtifacts(artifacts: Set<String>, version: String, artifactoryBaseUrl: String) : Map<String,URL> {
val urlMap = mutableMapOf<String,URL>()
artifacts.forEach { artifact ->
private fun resolveArtifacts(type: Type, version: String): Map<String, URL> {
if (type.requireAuthentication) Authenticator.setDefault(CordaArtifactoryAuthenticator)
val urlMap = mutableMapOf<String, URL>()
type.artifacts.forEach { artifact ->
val artifactoryBaseUrl = "$ARTIFACTORY_URL/${type.repositoryId}/${type.groupId.replace(".", "/")}"
val url = URL("$artifactoryBaseUrl/$artifact/$version/$artifact-$version.jar")
log.info("Artifactory resource URL: $url")
try {
url.openStream()
urlMap[artifact] = url
}
catch (ex: IOException) {
} catch (ex: IOException) {
log.warn("Unable to open artifactory resource URL: ${ex.message}")
}
}
@ -206,8 +199,11 @@ class Distribution private constructor(
* Get registered representation of a Corda distribution based on its version string.
* @param version The version of the Corda distribution
*/
private val entVersionScheme = "^\\d\\.\\d\\.\\d.*".toRegex() // ENTERPRISE version scheme x.y.z,
private val osVersionScheme = "^\\d\\.\\d.*".toRegex() // OS version scheme x.y
private val entVersionScheme = "^ENT-\\d\\.\\d.*".toRegex() // ENT version scheme x.y
private val osVersionScheme = "^OS-\\d\\.\\d.*".toRegex() // OS version scheme x.y
private val entVersionSnapshotScheme = "^ENT-\\d\\.\\d-SNAPSHOT\$".toRegex()
private val osVersionSnapshotScheme = "^OS-\\d\\.\\d-SNAPSHOT\$".toRegex()
fun fromVersionString(version: String): Distribution = when (version) {
"master" -> MASTER
@ -215,15 +211,19 @@ class Distribution private constructor(
"corda-3.0" -> fromArtifactory(Type.CORDA_OS, version)
"3.1-corda" -> fromArtifactory(Type.CORDA_OS, version)
"R3.CORDA-3.0.0-DEV-PREVIEW-3" -> fromArtifactory(Type.CORDA_ENTERPRISE, version)
else -> {
if (version.matches(entVersionScheme))
fromArtifactory(Type.CORDA_ENTERPRISE, version)
else if (version.matches(osVersionScheme))
fromArtifactory(Type.CORDA_OS, version)
else
distributions.firstOrNull { it.version == version }
?: throw CordaRuntimeException("Invalid Corda distribution for specified version: $version")
}
in entVersionSnapshotScheme -> fromArtifactory(Type.CORDA_ENTERPRISE_SNAPSHOT, version.substringAfter("ENT-"))
in osVersionSnapshotScheme -> fromArtifactory(Type.CORDA_OS_SNAPSHOT, version.substringAfter("OS-"))
in entVersionScheme -> fromArtifactory(Type.CORDA_ENTERPRISE, version.substringAfter("ENT-"))
in osVersionScheme -> fromArtifactory(Type.CORDA_OS, version.substringAfter("OS-"))
else -> distributions.firstOrNull { it.version == version } ?: throw CordaRuntimeException("Invalid Corda distribution for specified version: $version")
}
}
private object CordaArtifactoryAuthenticator : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(System.getenv("CORDA_ARTIFACTORY_USERNAME"), System.getenv("CORDA_ARTIFACTORY_PASSWORD").toCharArray())
}
}
}
private operator fun Regex.contains(text: CharSequence): Boolean = this.containsMatchIn(text)

View File

@ -14,6 +14,7 @@ import net.corda.behave.database.DatabaseConnection
import net.corda.behave.database.DatabaseType
import net.corda.behave.file.LogSource
import net.corda.behave.file.currentDirectory
import net.corda.behave.file.stagingRoot
import net.corda.behave.monitoring.PatternWatch
import net.corda.behave.node.configuration.*
import net.corda.behave.process.JarCommand
@ -25,6 +26,7 @@ import net.corda.behave.ssh.MonitoringSSHClient
import net.corda.behave.ssh.SSHClient
import net.corda.client.rpc.CordaRPCClient
import net.corda.client.rpc.CordaRPCClientConfiguration
import net.corda.core.internal.copyTo
import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.internal.exists
@ -35,7 +37,9 @@ import net.corda.core.utilities.minutes
import net.corda.core.utilities.seconds
import org.apache.commons.io.FileUtils
import java.net.InetAddress
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.time.Duration
import java.util.concurrent.CountDownLatch
@ -57,14 +61,15 @@ class Node(
private val logDirectory = runtimeDirectory / "logs"
private val command = JarCommand(
config.distribution.cordaJar,
arrayOf("--config", "node.conf"),
runtimeDirectory / "corda.jar",
arrayOf("--config", "node.conf", "--log-to-console", "--logging-level", "DEBUG"),
runtimeDirectory,
settings.timeout,
enableRemoteDebugging = false
)
private val isAliveLatch = PatternWatch(command.output, "Node for \".*\" started up and registered")
private val isNetworkMapReadyLatch = PatternWatch(command.output, "Done adding node with info")
private var isConfigured = false
@ -77,19 +82,31 @@ class Node(
private var haveDependenciesStopped = false
fun configure() {
if (isConfigured) { return }
if (isConfigured) {
return
}
isConfigured = true
log.info("Configuring {} ...", this)
serviceDependencies.addAll(config.database.type.dependencies(config))
config.distribution.ensureAvailable()
if (networkType == Distribution.Type.CORDA_ENTERPRISE && System.getProperty("USE_NETWORK_SERVICES") != null) {
val nodeDirectory = (rootDirectory / config.name).createDirectories()
config.writeToFile(nodeDirectory / "node.conf")
}
else {
config.writeToFile(rootDirectory / "${config.name}_node.conf")
}
val nodeDirectory = runtimeDirectory.createDirectories()
config.writeToFile(nodeDirectory / "node.conf")
// Copy jar to node folder, the bootstrapper will use this instead of the master jar.
config.distribution.cordaJar.copyTo(nodeDirectory / "corda.jar", StandardCopyOption.REPLACE_EXISTING)
installApps()
installDatabaseDriver(config.database.type)
}
private fun installDatabaseDriver(type: DatabaseType) {
if (type.driverJar != null) {
val driversDir = runtimeDirectory / "drivers"
log.info("Creating directory for drivers: $driversDir")
driversDir.toFile().mkdirs()
val driverPath = stagingRoot / "drivers" / type.driverJar
log.info("Copying database drivers from $driverPath to $driversDir")
Files.copy(driverPath, driversDir / type.driverJar, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING)
}
}
private fun initialiseDatabase(database: DatabaseConfiguration) {
@ -126,8 +143,9 @@ class Node(
}
}
fun waitUntilRunning(waitDuration: Duration? = null): Boolean {
val ok = isAliveLatch.await(waitDuration ?: settings.timeout)
fun waitUntilRunning(waitDuration: Duration = settings.timeout): Boolean {
val ok = isAliveLatch.await(waitDuration)
&& isNetworkMapReadyLatch.await(waitDuration)
if (!ok) {
log.warn("{} did not start up as expected within the given time frame", this)
} else {
@ -201,8 +219,7 @@ class Node(
log.info("Establishing HTTP connection to ${targetHost.host} on port ${targetHost.port} ...")
try {
return action(CordaRPCProxyClient(targetHost))
}
catch (e: Exception) {
} catch (e: Exception) {
log.warn("Failed to invoke http endpoint: ", e)
e.printStackTrace()
error("Failed to run http action")
@ -214,10 +231,14 @@ class Node(
}
fun startDependencies(): Boolean {
if (haveDependenciesStarted) { return true }
if (haveDependenciesStarted) {
return true
}
haveDependenciesStarted = true
if (serviceDependencies.isEmpty()) { return true }
if (serviceDependencies.isEmpty()) {
return true
}
log.info("Starting dependencies for {} ...", this)
val latch = CountDownLatch(serviceDependencies.size)
@ -240,10 +261,14 @@ class Node(
}
private fun stopDependencies() {
if (haveDependenciesStopped) { return }
if (haveDependenciesStopped) {
return
}
haveDependenciesStopped = true
if (serviceDependencies.isEmpty()) { return }
if (serviceDependencies.isEmpty()) {
return
}
log.info("Stopping dependencies for {} ...", this)
val latch = CountDownLatch(serviceDependencies.size)

View File

@ -148,9 +148,11 @@ open class Command(
fun run() = use { _ -> }
fun use(action: (Command) -> Unit): Int {
use {
try {
start()
action(this)
} finally {
close()
}
return exitCode
}

View File

@ -64,7 +64,6 @@ abstract class ContainerService(
log.info("Container $id info: $info")
client.startContainer(id)
true
} catch (e: Exception) {
id = null

View File

@ -0,0 +1,30 @@
/*
* R3 Proprietary and Confidential
*
* Copyright (c) 2018 R3 Limited. All rights reserved.
*
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
*
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.behave.service.database
import net.corda.behave.database.DatabaseType
import net.corda.behave.service.ServiceSettings
import net.corda.core.utilities.minutes
class Oracle11gService(
name: String,
port: Int,
password: String,
settings: ServiceSettings = ServiceSettings(startupTimeout = 2.minutes)
) : OracleService(name, port,"Oracle Database 11g Express Edition instance is already started", password, settings) {
override val baseImage = "sath89/oracle-xe-11g"
override val type = DatabaseType.ORACLE_11G
companion object {
const val driver = "ojdbc6.jar"
}
}

View File

@ -0,0 +1,30 @@
/*
* R3 Proprietary and Confidential
*
* Copyright (c) 2018 R3 Limited. All rights reserved.
*
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
*
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.behave.service.database
import net.corda.behave.database.DatabaseType
import net.corda.behave.service.ServiceSettings
import net.corda.core.utilities.minutes
class Oracle12cService(
name: String,
port: Int,
password: String,
settings: ServiceSettings = ServiceSettings(startupTimeout = 10.minutes)
) : OracleService(name, port, "Database initialized.", password, settings) {
override val baseImage = "sath89/oracle-12c"
override val type = DatabaseType.ORACLE_12C
companion object {
const val driver = "ojdbc6.jar"
}
}

View File

@ -0,0 +1,61 @@
/*
* R3 Proprietary and Confidential
*
* Copyright (c) 2018 R3 Limited. All rights reserved.
*
* The intellectual and technical concepts contained herein are proprietary to R3 and its suppliers and are protected by trade secret law.
*
* Distribution of this file or any portion thereof via any medium without the express permission of R3 is strictly prohibited.
*/
package net.corda.behave.service.database
import net.corda.behave.database.DatabaseConnection
import net.corda.behave.database.DatabaseType
import net.corda.behave.database.configuration.OracleConfigurationTemplate
import net.corda.behave.node.configuration.DatabaseConfiguration
import net.corda.behave.service.ContainerService
import net.corda.behave.service.ServiceSettings
abstract class OracleService(
name: String,
port: Int,
startupStatement: String,
private val password: String,
settings: ServiceSettings = ServiceSettings()
) : ContainerService(name, port, startupStatement, settings) {
override val internalPort = 1521
protected abstract val type: DatabaseType
override fun verify(): Boolean {
val config = DatabaseConfiguration(
type = type,
host = host,
port = port,
database = database,
schema = schema,
username = username,
password = password
)
val connection = DatabaseConnection(config, OracleConfigurationTemplate())
try {
connection.use {
return true
}
} catch (ex: Exception) {
log.warn(ex.message, ex)
ex.printStackTrace()
}
return false
}
companion object {
val host = "localhost"
val database = ""
val schema = ""
val username = "system"
val password = "oracle"
}
}

View File

@ -16,12 +16,13 @@ import net.corda.behave.database.configuration.PostgresConfigurationTemplate
import net.corda.behave.node.configuration.DatabaseConfiguration
import net.corda.behave.service.ContainerService
import net.corda.behave.service.ServiceSettings
import net.corda.core.utilities.minutes
class PostgreSQLService(
name: String,
port: Int,
private val password: String,
settings: ServiceSettings = ServiceSettings()
settings: ServiceSettings = ServiceSettings(startupTimeout = 2.minutes)
) : ContainerService(name, port, "database system is ready to accept connections", settings) {
override val baseImage = "postgres"

View File

@ -1,3 +1,4 @@
package net.corda.behave.service.database
import net.corda.behave.database.DatabaseConnection
import net.corda.behave.database.DatabaseType
@ -5,12 +6,13 @@ import net.corda.behave.database.configuration.SqlServerConfigurationTemplate
import net.corda.behave.node.configuration.DatabaseConfiguration
import net.corda.behave.service.ContainerService
import net.corda.behave.service.ServiceSettings
import net.corda.core.utilities.minutes
class SqlServerService(
name: String,
port: Int,
private val password: String,
settings: ServiceSettings = ServiceSettings()
settings: ServiceSettings = ServiceSettings(startupTimeout = 2.minutes)
) : ContainerService(name, port, "SQL Server is now ready for client connections", settings) {
override val baseImage = "microsoft/mssql-server-linux"

View File

@ -17,5 +17,6 @@ import org.junit.runner.RunWith
glue = ["net.corda.behave.scenarios"],
plugin = ["pretty"]
)
@Suppress("KDocMissingDocumentation")
class CucumberTest

View File

@ -114,4 +114,32 @@ class NetworkTests {
it.keepAlive(30.seconds)
}
}
@Ignore
@Test
fun `Corda Enterprise network of single node using Oracle 11g can be spun up`() {
val network = Network
.new(Distribution.Type.CORDA_ENTERPRISE)
.addNode(name = "Notary", distribution = Distribution.R3_MASTER, notaryType = NotaryType.NON_VALIDATING, databaseType = DatabaseType.ORACLE_11G)
.generate()
network.use {
it.waitUntilRunning(30.seconds)
it.keepAlive(30.seconds)
it.signal()
}
}
@Ignore
@Test
fun `Corda Enterprise network of single node using Oracle 12c can be spun up`() {
val network = Network
.new(Distribution.Type.CORDA_ENTERPRISE)
.addNode(name = "Notary", distribution = Distribution.R3_MASTER, notaryType = NotaryType.NON_VALIDATING, databaseType = DatabaseType.ORACLE_12C)
.generate()
network.use {
it.waitUntilRunning(30.seconds)
it.keepAlive(30.seconds)
it.signal()
}
}
}

View File

@ -14,20 +14,36 @@ class DistributionTest {
@Test
fun `resolve OS distribution from Artifactory`() {
val distribution = Distribution.fromArtifactory(Distribution.Type.CORDA_OS, "3.1-corda")
val distribution = Distribution.fromVersionString("OS-3.1-corda")
assertNotNull(distribution.artifactUrlMap)
assertThat(distribution.artifactUrlMap!!.size).isGreaterThanOrEqualTo(3)
// -DSTAGING_ROOT=${STAGING_ROOT}
distribution.ensureAvailable()
println("Check contents of ${distribution.path}")
}
@Test
fun `resolve Enterprise distribution from Artifactory`() {
val distribution = Distribution.fromArtifactory(Distribution.Type.CORDA_ENTERPRISE, "3.0.0-RC01")
val distribution = Distribution.fromVersionString("ENT-3.0")
assertNotNull(distribution.artifactUrlMap)
assertThat(distribution.artifactUrlMap!!.size).isGreaterThanOrEqualTo(5)
// -DSTAGING_ROOT=${STAGING_ROOT}
assertThat(distribution.artifactUrlMap!!.size).isGreaterThanOrEqualTo(4)
distribution.ensureAvailable()
println("Check contents of ${distribution.path}")
}
@Test
fun `resolve OS snapshot distribution from Artifactory`() {
val distribution = Distribution.fromVersionString("OS-4.0-SNAPSHOT")
assertNotNull(distribution.artifactUrlMap)
assertThat(distribution.artifactUrlMap!!.size).isGreaterThanOrEqualTo(3)
distribution.ensureAvailable()
println("Check contents of ${distribution.path}")
}
@Test
fun `resolve Enterprise snapshot distribution from Artifactory`() {
val distribution = Distribution.fromVersionString("ENT-4.0-SNAPSHOT")
assertNotNull(distribution.artifactUrlMap)
assertThat(distribution.artifactUrlMap!!.size).isGreaterThanOrEqualTo(4)
distribution.ensureAvailable()
println("Check contents of ${distribution.path}")
}

View File

@ -0,0 +1,27 @@
package net.corda.behave.service
import net.corda.behave.service.database.Oracle11gService
import net.corda.behave.service.database.Oracle12cService
import org.assertj.core.api.Assertions.assertThat
import org.junit.Ignore
import org.junit.Test
class OracleServiceTests {
@Test
fun `Oracle 11g can be started and stopped`() {
val service = Oracle11gService("test-oracle-11g", 1521, "oracle")
val didStart = service.start()
service.stop()
assertThat(didStart).isTrue()
}
@Ignore
@Test
fun `Oracle 12c can be started and stopped`() {
val service = Oracle12cService("test-oracle-12c", 1521, "oracle")
val didStart = service.start()
service.stop()
assertThat(didStart).isTrue()
}
}

View File

@ -29,7 +29,7 @@ sourceSets {
srcDir file('src/integration-test/kotlin')
}
}
scenarioTest {
scenario {
kotlin {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
@ -45,8 +45,8 @@ configurations {
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
scenarioTestCompile.extendsFrom testCompile
scenarioTestRuntime.extendsFrom testRuntime
scenarioCompile.extendsFrom testCompile
scenarioRuntime.extendsFrom testRuntime
}
dependencies {
@ -81,7 +81,7 @@ dependencies {
// Test dependencies
testCompile project(':node-driver')
scenarioTestCompile project(path: ":experimental:behave", configuration: 'testArtifacts')
scenarioCompile project(path: ":experimental:behave", configuration: 'testArtifacts')
testCompile "junit:junit:$junit_version"
testCompile "org.assertj:assertj-core:$assertj_version"
}
@ -167,3 +167,8 @@ task integrationTest(type: Test, dependsOn: []) {
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
}
task scenarioJar(type: Jar, dependsOn: classes) {
classifier "behave-test"
from sourceSets.scenario.output
}

View File

@ -1,9 +1,9 @@
@qa compatibility @node @cordapps
@qa @compatibility @node @cordapps
Feature: Compatibility - Corda distributions (OS and Enterprise) running different CorDapps
To support an interoperable Corda network, different CorDapps must have the ability to transact in mixed Corda (OS) and Corda Enterprise networks.
Scenario Outline: Run the SIMM valuation demo in a Corda OS Network.
Given a node PartyA of version <Corda-Node-Version> with proxy
Scenario Outline: Run the SIMM valuation demo in a Corda OS and Enterprise Network.
Given a node PartyA of version <Corda-Node-Version>
And node PartyA has app installed: <Cordapp-Name>
And a node PartyB of version <Corda-Node-Version>
And node PartyB has app installed: <Cordapp-Name>
@ -20,34 +20,15 @@ Feature: Compatibility - Corda distributions (OS and Enterprise) running differe
Examples:
| Corda-Node-Version | Cordapp-Name | Valuation |
| corda-3.0 | simm-valuation-demo | 12345 |
Scenario Outline: Run the SIMM valuation demo in a Corda Enterprise Network.
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
And node PartyA has app installed: <Cordapp-Name>
And a node PartyB of version <R3-Corda-Node-Version>
And node PartyB has app installed: <Cordapp-Name>
And a nonvalidating notary Notary of version <Corda-Node-Version>
When the network is ready
And node PartyA has loaded app <Cordapp-Name>
And node PartyB has loaded app <Cordapp-Name>
Then node PartyA can trade with node PartyB
And node PartyA vault contains 1 states
And node PartyB vault contains 1 states
And node PartyA can run portfolio valuation
And node PartyA portfolio valuation is <Valuation>
And node PartyB portfolio valuation is <Valuation>
Examples:
| R3-Corda-Node-Version | Cordapp-Name | Valuation |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | simm-valuation-demo | 12345 |
| OS-4.0-SNAPSHOT | simm-valuation-demo | 12345 |
| ENT-4.0-SNAPSHOT | simm-valuation-demo | 12345 |
Scenario Outline: Corda (OS) Node can transact with Corda Enterprise node using the SIMM valuation demo.
Given a node PartyA of version <Corda-Node-Version> with proxy
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
And node PartyA has app installed: <Cordapp-Name>
And a node PartyB of version <R3-Corda-Node-Version>
And a node PartyB of version <Corda-Node-Version>
And node PartyB has app installed: <Cordapp-Name>
And a nonvalidating notary Notary of version <Corda-Node-Version>
And a nonvalidating notary Notary of version <R3-Corda-Node-Version>
When the network is ready
And node PartyA has loaded app <Cordapp-Name>
And node PartyB has loaded app <Cordapp-Name>
@ -59,5 +40,9 @@ Feature: Compatibility - Corda distributions (OS and Enterprise) running differe
And node PartyB portfolio valuation is <Valuation>
Examples:
| Corda-Node-Version | R3-Corda-Node-Version | Cordapp-Name | Valuation |
| corda-3.0 | R3.CORDA-3.0.0-DEV-PREVIEW-3 | simm-valuation-demo | 12345 |
| R3-Corda-Node-Version | Corda-Node-Version | Cordapp-Name | Valuation |
| ENT-3.0 | ENT-4.0-SNAPSHOT | simm-valuation-demo | 12345 |
| ENT-3.0 | OS-4.0-SNAPSHOT | simm-valuation-demo | 12345 |
| ENT-3.0 | R3.CORDA-3.0.0-DEV-PREVIEW-3 | simm-valuation-demo | 12345 |
| ENT-3.0 | corda-3.0 | simm-valuation-demo | 12345 |
| ENT-3.0 | 3.1-corda | simm-valuation-demo | 12345 |

View File

@ -7,18 +7,33 @@
# ./IdeaProjects/corda-reviews/samples/simm-valuation-demo
# $ src/system-test/scenario/resources/scripts/run-behave-simm-valuation.sh
#
# NOTE: remember to setup your staging environment using the `prepare` script of gradle task.
#
CURRENT_DIR=$PWD
SAMPLE_HOME=$PWD
BEHAVE_DIR=${SAMPLE_HOME}/../../experimental/behave
BEHAVE_DIR=$CURRENT_DIR/../../experimental/behave
cd $BEHAVE_DIR
../../gradlew behaveJar
cd ${BEHAVE_DIR}
BEHAVE_JAR=$(ls ${BEHAVE_DIR}/build/libs/corda-behave-[0-9]*.jar | tail -n1)
DEMO_DIR=$CURRENT_DIR
cd $DEMO_DIR
../../gradlew scenarioJar
if [ ! -f "${BEHAVE_JAR}" ]; then
echo "Building behaveJar ..."
../../gradlew behaveJar
fi
BEHAVE_JAR=$(ls ${BEHAVE_DIR}/build/libs/corda-behave-[0-9]*.jar | tail -n1)
echo $BEHAVE_DIR
java -cp "$BEHAVE_DIR/build/libs/corda-behave.jar:$CURRENT_DIR/build/libs/simm-valuation-demo-behave-test.jar" net.corda.behave.scenarios.ScenarioRunner --glue "net.corda.behave.scenarios" -path ./src/system-test/scenario/resources/features/simm-valuation.feature -d
# -d to perform dry-run
cd ${SAMPLE_HOME}
SAMPLE_JAR=$(ls ${SAMPLE_HOME}/build/libs/simm-valuation-demo-*.jar | tail -n1)
if [ ! -f "${SAMPLE_JAR}" ]; then
echo "Building scenarioJar ..."
../../gradlew scenarioJar
fi
SAMPLE_JAR=$(ls ${SAMPLE_HOME}/build/libs/simm-valuation-demo-*.jar | tail -n1)
STAGING_ROOT="${STAGING_ROOT:-TMPDIR/staging}"
# QA interoperability
CMD="java -DSTAGING_ROOT=${STAGING_ROOT} -DDISABLE_CLEANUP=true -cp ${BEHAVE_JAR}:${SAMPLE_JAR} net.corda.behave.scenarios.ScenarioRunner -path ${SAMPLE_HOME}/src/system-test/scenario/resources/features/simm-valuation.feature"
# -d to perform dry-run
echo "Executing: ${CMD}"
eval `${CMD}`

View File

@ -3,24 +3,24 @@ Feature: QA Interoperability
To support an interoperable Corda network, different CorDapps must have the ability to transact in mixed Corda (OS) and Corda Enterprise networks.
Scenario Outline: Corda (OS) Node can transact with Corda Enterprise node, in a Corda Enterprise configured network.
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Given a node PartyA of version <Party-A-Version>
And node PartyA has the finance app installed
And a node PartyB of version <Corda-Node-Version>
And a node PartyB of version <Party-B-Version>
And node PartyB has the finance app installed
And a nonvalidating notary Notary of version <R3-Corda-Node-Version>
And a nonvalidating notary Notary of version <Party-A-Version>
When the network is ready
Then node PartyA can issue 1000 <Currency>
And node PartyA can transfer 100 <Currency> to node PartyB
Examples:
| R3-Corda-Node-Version | Corda-Node-Version | Currency |
| r3-master | corda-master | GBP |
| corda-3.0 | corda-3.1 | GBP |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.0 | GBP |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.1 | GBP |
| Party-A-Version | Party-B-Version | Currency |
| ENT-3.0 | ENT-4.0-SNAPSHOT | GBP |
| ENT-3.0 | OS-4.0-SNAPSHOT | GBP |
| ENT-3.0 | 3.1-corda | GBP |
| ENT-3.0 | corda-3.0 | GBP |
Scenario Outline: Corda (OS) Node using H2 database can transact with Corda Enterprise node using a sql-server database
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Scenario Outline: Corda (OS) Node using H2 database can transact with Corda Enterprise node using a commercial database
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA uses database of type <Database-Type>
And node PartyA has the finance app installed
And a node PartyB of version <Corda-Node-Version>
@ -31,24 +31,32 @@ Feature: QA Interoperability
And node PartyA can transfer 100 <Currency> to node PartyB
Examples:
| R3-Corda-Node-Version | Corda-Node-Version | Currency | Database-Type |
| r3-master | corda-master | GBP | sql-server |
| corda-3.0 | corda-3.1 | GBP | sql-server |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.0 | GBP | sql-server |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.1 | GBP | sql-server |
| r3-master | corda-master | GBP | postgres |
| corda-3.0 | corda-3.1 | GBP | postgres |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.0 | GBP | postgres |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.1 | GBP | postgres |
| R3-Corda-Node-Version | Corda-Node-Version | Currency | Database-Type |
| ENT-3.0 | ENT-4.0-SNAPSHOT | GBP | sql-server |
| ENT-3.0 | OS-4.0-SNAPSHOT | GBP | sql-server |
| ENT-3.0 | 3.1-corda | GBP | sql-server |
| ENT-3.0 | corda-3.0 | GBP | sql-server |
| ENT-3.0 | ENT-4.0-SNAPSHOT | GBP | postgres |
| ENT-3.0 | OS-4.0-SNAPSHOT | GBP | postgres |
| ENT-3.0 | 3.1-corda | GBP | postgres |
| ENT-3.0 | corda-3.0 | GBP | postgres |
| ENT-3.0 | ENT-4.0-SNAPSHOT | GBP | oracle11g |
| ENT-3.0 | OS-4.0-SNAPSHOT | GBP | oracle11g |
| ENT-3.0 | 3.1-corda | GBP | oracle11g |
| ENT-3.0 | corda-3.0 | GBP | oracle11g |
| ENT-3.0 | ENT-4.0-SNAPSHOT | GBP | oracle12c |
| ENT-3.0 | OS-4.0-SNAPSHOT | GBP | oracle12c |
| ENT-3.0 | 3.1-corda | GBP | oracle12c |
| ENT-3.0 | corda-3.0 | GBP | oracle12c |
Scenario Outline: Corda Enterprise network with Corda Enterprise nodes using different database providers and versions transacting between each other
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA uses database of type <Database-Type-1>
And node PartyA has the finance app installed
And a node PartyB of version <R3-Corda-Node-Version> with proxy
And a node PartyB of version <R3-Corda-Node-Version>
And node PartyB uses database of type <Database-Type-2>
And node PartyB has the finance app installed
And a node PartyC of version <R3-Corda-Node-Version> with proxy
And a node PartyC of version <R3-Corda-Node-Version>
And node PartyC uses database of type <Database-Type-3>
And node PartyC has the finance app installed
And a nonvalidating notary Notary of version <R3-Corda-Node-Version>
@ -59,18 +67,17 @@ Feature: QA Interoperability
And node PartyC can transfer 100 <Currency> to node PartyA
Examples:
| R3-Corda-Node-Version | Currency | Database-Type-1 | Database-Type-2 | Database-Type-3 |
| r3-master | GBP | h2 | sql-server | postgres |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | GBP | h2 | sql-server | postgres |
| R3-Corda-Node-Version | Currency | Database-Type-1 | Database-Type-2 | Database-Type-3 |
| ENT-3.0 | GBP | h2 | sql-server | postgres |
Scenario Outline: Mixed OS and Corda Enterprise network using different database providers and versions transacting between each other
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA uses database of type <Database-Type-1>
And node PartyA has the finance app installed
And a node PartyB of version <R3-Corda-Node-Version> with proxy
And a node PartyB of version <R3-Corda-Node-Version>
And node PartyB uses database of type <Database-Type-2>
And node PartyB has the finance app installed
And a node PartyC of version <Corda-Node-Version> with proxy
And a node PartyC of version <Corda-Node-Version>
And node PartyC uses database of type <Database-Type-3>
And node PartyC has the finance app installed
And a nonvalidating notary Notary of version <R3-Corda-Node-Version>
@ -81,7 +88,8 @@ Feature: QA Interoperability
And node PartyC can transfer 100 <Currency> to node PartyA
Examples:
| R3-Corda-Node-Version | Corda-Node-Version | Currency | Database-Type-1 | Database-Type-2 | Database-Type-3 |
| r3-master | corda-master | GBP | sql-server | postgres | h2 |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.0 | GBP | sql-server | postgres | h2 |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | corda-3.1 | GBP | sql-server | postgres | h2 |
| R3-Corda-Node-Version | Corda-Node-Version | Currency | Database-Type-1 | Database-Type-2 | Database-Type-3 |
| ENT-3.0 | ENT-4.0-SNAPSHOT | GBP | sql-server | postgres | h2 |
| ENT-3.0 | OS-4.0-SNAPSHOT | GBP | sql-server | postgres | h2 |
| ENT-3.0 | 3.1-corda | GBP | sql-server | postgres | h2 |
| ENT-3.0 | corda-3.0 | GBP | sql-server | postgres | h2 |

View File

@ -0,0 +1,18 @@
@logging @startup
Feature: Startup Information - Logging
A Corda node should inform the user of important parameters during startup so that he/she can confirm the setup and
configure / connect relevant software to said node.
Scenario Outline: Node shows version information on startup
Given a node PartyA of version <Node-Version>
When the network is ready
Then node PartyA is on platform version <Platform-Version>
And node PartyA is on release version <Release-Version>
Examples:
| Node-Version | Platform-Version | Release-Version |
| ENT-4.0-SNAPSHOT | 4 | 4.0-SNAPSHOT |
| ENT-3.0 | 3 | 3.0 |
| OS-4.0-SNAPSHOT | 4 | 4.0-SNAPSHOT |
| 3.1-corda | 3 | 3.1-corda |
| corda-3.0 | 3 | corda-3.0 |

View File

@ -6,14 +6,30 @@
# R3CORDA_HOME => git clone https://github.com/corda/enterprise
#
# $ testing/qa/behave/compatibility/resources/scripts/run-interoperability.sh
#
# Note: you can also pass a single command line argument to specify a range (one or more) of scenarios to execute
# e.g.
# /enterprise/testing/qa/behave/compatibility/resources/features/interoperability.feature:5
R3CORDA_HOME=$PWD
BEHAVE_DIR=${R3CORDA_HOME}/experimental/behave
cd ${BEHAVE_DIR}
../../gradlew behaveJar
cd ${BEHAVE_DIR}
BEHAVE_JAR=$(ls build/libs/corda-behave-*.jar | tail -n1)
if [ ! -f "${BEHAVE_JAR}" ]; then
echo "Building behaveJar ..."
../../gradlew behaveJar
fi
STAGING_ROOT="${STAGING_ROOT:-TMPDIR/staging}"
# QA interoperability (specify -d for dry-run)
java -DSTAGING_ROOT=${STAGING_ROOT} -DDISABLE_CLEANUP=true -jar ${BEHAVE_JAR} --glue net.corda.behave.scenarios -path ${R3CORDA_HOME}/testing/qa/behave/compatibility/resources/features/interoperability.feature
CMD="java -DSTAGING_ROOT=${STAGING_ROOT} -DDISABLE_CLEANUP=true -jar ${BEHAVE_JAR} -path ${R3CORDA_HOME}/testing/qa/behave/compatibility/resources/features/interoperability.feature"
if [ ! -z "$1" ]
then
java -DSTAGING_ROOT=${STAGING_ROOT} -DDISABLE_CLEANUP=true -jar ${BEHAVE_JAR} -path $1
exit
fi
echo "Executing: ${CMD}"
eval `${CMD}`

View File

@ -3,7 +3,7 @@ Feature: QA Operational
An Corda Enterprise network must support cash transactions using multiple database providers.
Scenario Outline: QA: Stand up a basic Corda Enterprise Network with one node that can verify its identity
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA has the finance app installed
When the network is ready
Then node PartyA is on platform version 4
@ -15,7 +15,7 @@ Feature: QA Operational
| r3-master | 3.0.0-SNAPSHOT |
Scenario Outline: QA: Stand up a basic Corda Enterprise Network with one node and a notary; node can issue cash to itself
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Given a node PartyA of version <R3-Corda-Node-Version>
And a nonvalidating notary Notary of version <R3-Corda-Node-Version>
And node PartyA has the finance app installed
When the network is ready
@ -36,7 +36,7 @@ Feature: QA Operational
| r3-master | SQL Server |
Scenario Outline: QA: Node using H2 can transact with node using SQL Server, in a Corda Enterprise configured network.
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA uses database of type <Database-Type>
And node PartyA has the finance app installed
And a node PartyB of version <R3-Corda-Node-Version>
@ -61,7 +61,7 @@ Feature: QA Operational
| r3-master | postgres |
Scenario Outline: QA: Node using H2 can transact with node using Postgres, in a Corda Enterprise configured network.
Given a node PartyA of version <R3-Corda-Node-Version> with proxy
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA uses database of type <Database-Type>
And node PartyA has the finance app installed
And a node PartyB of version <R3-Corda-Node-Version>
@ -74,3 +74,53 @@ Feature: QA Operational
Examples:
| R3-Corda-Node-Version | Currency | Database-Type |
| r3-master | GBP | postgres |
Scenario Outline: User can connect to a Corda Enterprise node using an Oracle 11g database
Given a node PartyA of version <Node-Version>
And node PartyA uses database of type <Database-Type>
When the network is ready
Then user can connect to the database of node PartyA
Examples:
| Node-Version | Database-Type |
| r3-master | oracle11g |
Scenario Outline: QA: Node using H2 can transact with node using Oracle 11g, in a Corda Enterprise configured network.
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA uses database of type <Database-Type>
And node PartyA has the finance app installed
And a node PartyB of version <R3-Corda-Node-Version>
And node PartyB has the finance app installed
And a nonvalidating notary Notary of version <R3-Corda-Node-Version>
When the network is ready
Then node PartyA can issue 1000 <Currency>
And node PartyA can transfer 100 <Currency> to node B
Examples:
| R3-Corda-Node-Version | Currency | Database-Type |
| r3-master | GBP | oracle11g |
Scenario Outline: User can connect to a Corda Enterprise node using an Oracle 12c database
Given a node PartyA of version <Node-Version>
And node PartyA uses database of type <Database-Type>
When the network is ready
Then user can connect to the database of node PartyA
Examples:
| Node-Version | Database-Type |
| r3-master | oracle12c |
Scenario Outline: QA: Node using H2 can transact with node using Oracle 12c, in a Corda Enterprise configured network.
Given a node PartyA of version <R3-Corda-Node-Version>
And node PartyA uses database of type <Database-Type>
And node PartyA has the finance app installed
And a node PartyB of version <R3-Corda-Node-Version>
And node PartyB has the finance app installed
And a nonvalidating notary Notary of version <R3-Corda-Node-Version>
When the network is ready
Then node PartyA can issue 1000 <Currency>
And node PartyA can transfer 100 <Currency> to node B
Examples:
| R3-Corda-Node-Version | Currency | Database-Type |
| r3-master | GBP | oracle12c |

View File

@ -10,11 +10,23 @@
R3CORDA_HOME=$PWD
BEHAVE_DIR=${R3CORDA_HOME}/experimental/behave
cd ${BEHAVE_DIR}
../../gradlew behaveJar
cd ${BEHAVE_DIR}
BEHAVE_JAR=$(ls build/libs/corda-behave-*.jar | tail -n1)
if [ ! -f "${BEHAVE_JAR}" ]; then
echo "Building behaveJar ..."
../../gradlew behaveJar
fi
STAGING_ROOT="${STAGING_ROOT:-TMPDIR/staging}"
# QA functional (specify -d for dry-run)
java -DSTAGING_ROOT=${STAGING_ROOT} -DDISABLE_CLEANUP=true -jar ${BEHAVE_JAR} --glue net.corda.behave.scenarios -path ${R3CORDA_HOME}/testing/qa/behave/functional/resources/features/functional.feature
CMD="java -DSTAGING_ROOT=${STAGING_ROOT} -DDISABLE_CLEANUP=true -jar ${BEHAVE_JAR} -path ${R3CORDA_HOME}/testing/qa/behave/functional/resources/features/functional.feature"
if [ ! -z "$1" ]
then
java -DSTAGING_ROOT=${STAGING_ROOT} -DDISABLE_CLEANUP=true -jar ${BEHAVE_JAR} -path $1
exit
fi
echo "Executing: ${CMD}"
eval `${CMD}`