Corda Behave framework updates to decouple from Network Services (#914)

* Added new 'eventHorizonDays' configuration item.

* Added custom authenticator to provide ARTIFACTORY credentials upon resolving protected internal URL.

* Re-pointed functional test scenarios to point to Enterprise master.

* Enterprise corda network scenarios to use NetworkBootstrapper tool (instead of Doorman/NMS) since decision made by Product Management to split out Doorman/NMS from Enterprise.

* Configuration parameter changed to 'runMigration' since DP3.

* Fixed problem with logger upon startup.

* General improvements and additions to setup and execution scripts (eg. SIMM valuation demo now consists of 3 separate jars)

* Updates to decouple from Network Services.

* Download all JARs from artifactory for a given published distribution.

* Add TODOs for Doorman/NMS rework.

* Addressing TL PR review comments.

* Additional instructions for setting up the environment and running QA tests.

* Fixed repository URL references.
This commit is contained in:
josecoll 2018-06-05 15:02:07 +01:00 committed by GitHub
parent 4de4e8a3ef
commit c2f22e18a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 435 additions and 80 deletions

View File

@ -55,4 +55,35 @@ the following parameter to the Gradle command:
$ ../../gradlew scenario -Ptags="@cash"
# or
$ ../../gradlew scenario -Ptags="@cash,@logging"
```
```
# Environment variables and system properties
The following environment variables must be set to enable access to the internal R3 Artifactory repository hosting Enterprise distributions:
https://ci-artifactory.corda.r3cev.com/artifactory/r3-corda-releases
```bash
CORDA_ARTIFACTORY_USERNAME
CORDA_ARTIFACTORY_PASSWORD
```
The following system properties may be passed to the Cucumber and ScenarioRunner run-time processes:
* `STAGING_ROOT` to specify the filesystem location of the Corda distributions to be used (as setup by the prepare.sh script)
```bash
e.g. -DSTAGING_ROOT=$HOME/staging
```
* `USE_NETWORK_SERVICES` specifies to use the Doorman/NMS service to perform setup of an Enterprise network.
By default both OS and Enterprise scenarios will use the [Network Bootstrapper utility](https://docs.corda.net/head/setting-up-a-corda-network.html#bootstrapping-the-network) to create a Corda network.
```bash
e.g. -DUSE_NETWORK_SERVICES
```
* `DISABLE_CLEANUP` to prevent clean-up of runtime directories after successfully running tests.
```bash
e.g. -DDISABLE_CLEANUP
```

View File

@ -7,13 +7,21 @@ set -x
# corda-master => git clone https://github.com/corda/corda
# r3corda-master => git clone https://github.com/corda/enterprise
VERSION=r3corda-master
STAGING_DIR=~/staging
STAGING_DIR="${STAGING_ROOT:-$TMPDIR/staging}"
echo "Staging directory: $STAGING_DIR"
CORDA_DIR=${STAGING_DIR}/corda/${VERSION}
echo "Corda staging directory: $CORDA_DIR"
CORDAPP_DIR=${CORDA_DIR}/apps
echo "CorDapp staging directory: $CORDAPP_DIR"
DRIVERS_DIR=${STAGING_DIR}/drivers
echo "Drivers staging directory: $DRIVERS_DIR"
# Set up directories
mkdir -p ${STAGING_DIR}
mkdir -p ${STAGING_DIR} || { echo "Unable to create directory $STAGING_DIR"; exit; }
mkdir -p ${CORDA_DIR}
mkdir -p ${CORDAPP_DIR}
mkdir -p ${DRIVERS_DIR}
@ -27,8 +35,14 @@ cp -v $(ls node/capsule/build/libs/corda-*.jar | tail -n1) ${CORDA_DIR}/corda.ja
cp -v $(ls finance/build/libs/corda-finance-*.jar | tail -n1) ${CORDAPP_DIR}
# Copy sample Cordapps
# SIMM valuation demo
./gradlew samples:simm-valuation-demo:jar
cp -v $(ls samples/simm-valuation-demo/build/libs/simm-valuation-demo-*.jar | tail -n1) ${CORDAPP_DIR}
./gradlew samples:simm-valuation-demo:contracts-states:jar
cp -v $(ls samples/simm-valuation-demo/contracts-states/build/libs/contracts-states-*.jar | tail -n1) ${CORDAPP_DIR}
./gradlew samples:simm-valuation-demo:flows:jar
cp -v $(ls samples/simm-valuation-demo/flows/build/libs/flows-*.jar | tail -n1) ${CORDAPP_DIR}
# Download database drivers
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
@ -39,11 +53,17 @@ curl -L "https://github.com/Microsoft/mssql-jdbc/releases/download/v6.2.2/mssql-
./gradlew buildBootstrapperJar
cp -v $(ls tools/bootstrapper/build/libs/*.jar | tail -n1) ${CORDA_DIR}/network-bootstrapper.jar
# build and distribute Doorman/NMS
./gradlew network-management:capsule:buildDoormanJAR
cp -v $(ls network-management/capsule/build/libs/doorman-*.jar | tail -n1) ${CORDA_DIR}/doorman.jar
# TODO: resolve Doorman/NMS artifacts from new artifactory location.
# Doorman/NMS has moved to a separate repo: https://github.com/corda/network-services,
# now follows a different release cycle (and versioning scheme), and is published to a new artifactory location:
# https://ci-artifactory.corda.r3cev.com/artifactory/r3-corda-releases/com/r3/corda/networkservices/doorman/
# 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
# 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
cp -v $(ls testing/qa/behave/tools/rpc-proxy/build/libs/corda-rpcProxy*.jar | tail -n1) ${CORDA_DIR}/corda-rpcProxy.jar
cp -v testing/qa/behave/tools/rpc-proxy/startRPCproxy.sh ${CORDA_DIR}

View File

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

View File

@ -108,10 +108,11 @@ class Network private constructor(
throw CordaException("Unable to configure nodes in Corda network. Please check logs in $directory")
}
if (networkType == Distribution.Type.CORDA_ENTERPRISE)
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)
network.bootstrapDoorman()
else
network.bootstrapLocalNetwork()
network.bootstrapLocalNetwork(networkType)
return network
}
}
@ -147,6 +148,10 @@ class Network private constructor(
*/
private fun bootstrapDoorman() {
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
signalFailure("Bootstrapping a Corda Enterprise network using the Doorman is no longer supported; exiting ...")
return
// WARNING!! Need to use the correct bootstrapper
// only if using OS nodes (need to choose the latest version)
val r3node = nodes.values
@ -158,21 +163,25 @@ class Network private constructor(
val doormanTargetDirectory = targetDirectory / "doorman"
source.toFile().copyRecursively(doormanTargetDirectory.toFile(), true)
// Use master version of Bootstrapper
val doormanJar = Distribution.R3_MASTER.doormanJar
log.info("DoormanJar URL: $doormanJar\n")
// 1. Create key stores for local signer
// java -jar doorman-<version>.jar --mode ROOT_KEYGEN
log.info("Doorman target directory: $doormanTargetDirectory")
runCommand(JarCommand(distribution.doormanJar,
runCommand(JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf", "--mode", "ROOT_KEYGEN", "--trust-store-password", "password"),
doormanTargetDirectory, timeout))
// java -jar doorman-<version>.jar --mode CA_KEYGEN
runCommand(JarCommand(distribution.doormanJar,
runCommand(JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf", "--mode", "CA_KEYGEN"),
doormanTargetDirectory, timeout))
// 2. Start the doorman service for notary registration
doormanNMS = JarCommand(distribution.doormanJar,
doormanNMS = JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node-init.conf"),
doormanTargetDirectory, timeout)
@ -216,13 +225,13 @@ class Network private constructor(
// 6. Load initial network parameters file for network map service
val networkParamsConfig = if (notaryNodes.isEmpty()) "network-parameters-without-notary.conf" else "network-parameters.conf"
val updateNetworkParams = JarCommand(distribution.doormanJar,
val updateNetworkParams = JarCommand(doormanJar,
arrayOf("--config-file", "$doormanTargetDirectory/node.conf", "--set-network-parameters", "$doormanTargetDirectory/$networkParamsConfig"),
doormanTargetDirectory, timeout)
runCommand(updateNetworkParams)
// 7. Start a fully configured Doorman / NMS
doormanNMS = JarCommand(distribution.doormanJar,
doormanNMS = JarCommand(doormanJar,
arrayOf("--config-file", "$doormanConfigDirectory/node.conf"),
doormanTargetDirectory, timeout)
@ -283,12 +292,14 @@ class Network private constructor(
return command
}
private fun bootstrapLocalNetwork() {
val bootstrapper = nodes.values
.filter { it.config.distribution.type != Distribution.Type.CORDA_ENTERPRISE }
.sortedByDescending { it.config.distribution.version }
.first()
.config.distribution.networkBootstrapper
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
}
log.info("Bootstrapper URL: $bootstrapper\n")
if (!bootstrapper.exists()) {
signalFailure("Network bootstrapping tool does not exist; exiting ...")
@ -320,7 +331,7 @@ class Network private constructor(
runCommand(rpcProxyCommand)
}
else {
log.warn("Missing RPC proxy startup script. Continuing ...")
log.warn("Missing RPC proxy startup script ($startProxyScript). Continuing ...")
}
}

View File

@ -17,8 +17,13 @@ import net.corda.core.internal.createDirectories
import net.corda.core.internal.div
import net.corda.core.internal.exists
import net.corda.core.utilities.contextLogger
import java.io.IOException
import java.net.Authenticator
import java.net.PasswordAuthentication
import java.net.URL
import java.nio.file.Path
import java.nio.file.StandardCopyOption
/**
* Corda distribution.
@ -41,9 +46,9 @@ class Distribution private constructor(
file: Path? = null,
/**
* The URL of the distribution fat JAR, if available.
* Map of all distribution JAR artifacts from artifactory, if available.
*/
val url: URL? = null,
val artifactUrlMap: Map<String,URL>? = null,
/**
* The Docker image details, if available
@ -86,10 +91,22 @@ class Distribution private constructor(
*/
fun ensureAvailable() {
if (cordaJar.exists()) return
val url = checkNotNull(url) { "File not found $cordaJar" }
try {
cordaJar.parent.createDirectories()
url.openStream().use { it.copyTo(cordaJar) }
path.createDirectories()
cordappDirectory.createDirectories()
Authenticator.setDefault(object : Authenticator() {
override fun getPasswordAuthentication(): PasswordAuthentication {
return PasswordAuthentication(System.getenv("CORDA_ARTIFACTORY_USERNAME"), System.getenv("CORDA_ARTIFACTORY_PASSWORD").toCharArray())
}
})
artifactUrlMap!!.forEach { artifactName, artifactUrl ->
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)
}
}
} catch (e: Exception) {
if ("HTTP response code: 401" in e.message!!) {
log.warn("CORDA_ARTIFACTORY_USERNAME ${System.getenv("CORDA_ARTIFACTORY_USERNAME")}")
@ -105,9 +122,11 @@ class Distribution private constructor(
*/
override fun toString() = "Corda(version = $version, path = $cordaJar)"
enum class Type {
CORDA_OS,
CORDA_ENTERPRISE
enum class Type(val artifacts: Set<String>) {
CORDA_OS(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-bridgeserver", "migration-tool"))
}
companion object {
@ -122,22 +141,43 @@ class Distribution private constructor(
val R3_MASTER = fromJarFile(Type.CORDA_ENTERPRISE, "r3corda-master")
/**
* Get representation of a Corda distribution from Artifactory based on its version string.
* Get all jar artifacts from Artifactory for a given distribution and version of Corda.
* @param type The Corda distribution type.
* @param version The version of the Corda distribution.
*/
fun fromArtifactory(type: Type, version: String): Distribution {
val url =
when (type) {
Type.CORDA_OS -> URL("https://ci-artifactory.corda.r3cev.com/artifactory/corda-releases/net/corda/corda/$version/corda-$version.jar")
Type.CORDA_ENTERPRISE -> URL("https://ci-artifactory.corda.r3cev.com/artifactory/r3-corda-releases/com/r3/corda/corda/$version/corda-$version.jar")
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")
}
log.info("Artifactory URL: $url\n")
val distribution = Distribution(type, version, url = url)
}
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 ->
val url = URL("$artifactoryBaseUrl/$artifact/$version/$artifact-$version.jar")
log.info("Artifactory resource URL: $url")
try {
url.openStream()
urlMap[artifact] = url
}
catch (ex: IOException) {
log.warn("Unable to open artifactory resource URL: ${ex.message}")
}
}
return urlMap
}
/**
* Get representation of a Corda distribution based on its version string and fat JAR path.
* @param type The Corda distribution type.
@ -166,13 +206,24 @@ 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
fun fromVersionString(version: String): Distribution = when (version) {
"master" -> MASTER
"r3-master" -> R3_MASTER
"corda-3.0" -> fromArtifactory(Type.CORDA_OS, version)
"corda-3.1" -> 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 -> distributions.firstOrNull { it.version == version } ?: throw CordaRuntimeException("Unable to locate Corda distribution for version: $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")
}
}
}
}

View File

@ -45,7 +45,7 @@ import java.util.concurrent.CountDownLatch
*/
class Node(
val config: Configuration,
private val rootDirectory: Path = currentDirectory,
val rootDirectory: Path = currentDirectory,
private val settings: ServiceSettings = ServiceSettings(),
val rpcProxy: Boolean = false,
val networkType: Distribution.Type
@ -95,13 +95,13 @@ class Node(
log.info("Configuring {} ...", this)
serviceDependencies.addAll(config.database.type.dependencies(config))
config.distribution.ensureAvailable()
if (networkType == Distribution.Type.CORDA_OS) {
config.writeToFile(rootDirectory / "${config.name}_node.conf")
}
else {
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")
}
installApps()
}
@ -273,8 +273,7 @@ class Node(
}
private fun installApps() {
val version = config.distribution.version
val appDirectory = stagingRoot / "corda" / version / "apps"
val appDirectory = config.distribution.cordappDirectory
if (appDirectory.exists()) {
val targetAppDirectory = runtimeDirectory / "cordapps"
FileUtils.copyDirectory(appDirectory.toFile(), targetAppDirectory.toFile())
@ -387,9 +386,10 @@ class Node(
fun build(): Node {
val name = name ?: error("Node name not set")
val directory = directory ?: error("Runtime directory not set")
val compatibilityZoneURL =
if (networkType == Distribution.Type.CORDA_ENTERPRISE)
compatibilityZoneURL ?: "http://localhost:1300"
// TODO: rework how we use the Doorman/NMS (now these are a separate product / distribution)
val compatibilityZoneURL = null
if (networkType == Distribution.Type.CORDA_ENTERPRISE && System.getProperty("USE_NETWORK_SERVICES") != null)
"http://localhost:1300" // TODO: add additional USE_NETWORK_SERVICES_URL to specify location of existing operational environment to use.
else null
return Node(
Configuration(

View File

@ -36,7 +36,7 @@ class Configuration(
vararg configElements: ConfigurationTemplate
) {
private val developerMode = (distribution.type == Distribution.Type.CORDA_OS)
private val developerMode = System.getProperty("USE_NETWORK_SERVICES") == null
val cordaX500Name: CordaX500Name by lazy({
CordaX500Name(name, location, country)

View File

@ -60,7 +60,7 @@ open class Command(
private val thread = Thread(Runnable {
try {
log.info("Command: $command")
log.info("Executing command: $command from directory: $directory")
val processBuilder = ProcessBuilder(command)
.directory(directory.toFile())
.redirectErrorStream(true)

View File

@ -1,3 +1,4 @@
minimumPlatformVersion = 1
maxMessageSize = 10485760
maxTransactionSize = 10485760
eventHorizonDays = 30

View File

@ -5,3 +5,4 @@ notaries : [{
minimumPlatformVersion = 1
maxMessageSize = 10485760
maxTransactionSize = 10485760
eventHorizonDays = 30

View File

@ -10,13 +10,13 @@
package net.corda.behave.scenarios.helpers
import net.corda.behave.logging.getLogger
import net.corda.behave.scenarios.ScenarioState
import net.corda.core.messaging.CordaRPCOps
import net.corda.core.utilities.contextLogger
abstract class Substeps(protected val state: ScenarioState) {
protected val log = contextLogger()
protected val log = getLogger<Substeps>()
protected fun withNetwork(action: ScenarioState.() -> Unit) =
state.withNetwork(action)

View File

@ -14,7 +14,7 @@ cd ${BUILD_DIR}
../../gradlew behaveJar
BEHAVE_JAR=$(ls build/libs/corda-behave-*.jar | tail -n1)
STAGING_ROOT=~/staging
STAGING_ROOT="${STAGING_ROOT:-TMPDIR/staging}"
# startup
java -DSTAGING_ROOT=${STAGING_ROOT} -jar ${BEHAVE_JAR} --glue net.corda.behave.scenarios -path ./src/scenario/resources/features/startup/logging.feature

View File

@ -0,0 +1,34 @@
package net.corda.behave.node
import org.assertj.core.api.Assertions.assertThat
import org.junit.Test
import kotlin.test.assertNotNull
class DistributionTest {
/**
* NOTE: ensure you have correctly setup the system environment variables:
* CORDA_ARTIFACTORY_USERNAME
* CORDA_ARTIFACTORY_PASSWORD
*/
@Test
fun `resolve OS distribution from Artifactory`() {
val distribution = Distribution.fromArtifactory(Distribution.Type.CORDA_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")
assertNotNull(distribution.artifactUrlMap)
assertThat(distribution.artifactUrlMap!!.size).isGreaterThanOrEqualTo(5)
// -DSTAGING_ROOT=${STAGING_ROOT}
distribution.ensureAvailable()
println("Check contents of ${distribution.path}")
}
}

View File

@ -1,3 +1,6 @@
Overview
========
The Behave Cucumber Scenarios defined under these sub-directories exercise Corda Enterprise and OS Corda distributions to include:
- Open Source master
- Corda Enterprise master
@ -30,4 +33,197 @@ Further goals of this project are to:
- automatically generate and register Docker images with target Azure Test Environments (eg. Functional/QA, CTS)
- effect execution of scenarios in specified Target Environments
- use Before and After hooks to pre-configure Target Environments to allow batch running of multiple scenarios (eg. a given
feature will specify the environment once for one or many scenarios)
feature will specify the environment once for one or many scenarios)
QA setup and usage instructions
===============================
Setup
-----
Set up the staging area which will hold all the distributions of Corda referenced in the test scenarios:
- specify the staging root directory:
```bash
$export STAGING_ROOT=$HOME/staging
```
- if any of your tests are referencing a master version of [Corda OS](https://github.com/corda/corda), checkout the latest version of the Open Source repo and run:
```bash
$ cd experimental/behave
$ ./prepare.sh
```
You should now see the following artifacts in your staging area:
```bash
$ ls -lR /Users/home/staging/corda/corda-master
total 285440
drwxr-xr-x 3 user staff 96 4 Jun 16:11 apps
-rw-r--r-- 1 user staff 55439705 4 Jun 16:11 corda.jar
-rw-r--r-- 1 user staff 90699598 4 Jun 16:11 network-bootstrapper.jar
/Users/home/staging/corda/corda-master/apps:
total 4688
-rw------- 1 user staff 2396954 4 Jun 16:11 corda-finance-4.0-SNAPSHOT.jar
```
- similarly, if any of your tests are referencing a master version of [Corda Enterprise](https://github.com/corda/enterprise), checkout the latest version of the Enterprise repo and run:
```bash
$ cd experimental/behave
$ ./prepare.sh
```
You should now see the following artifacts in your staging area:
```bash
$ ls -lR /Users/home/staging/corda/r3corda-master/
total 503264
drwxr-xr-x 6 user staff 192 4 Jun 16:39 apps
-rw-r--r-- 1 user staff 6239281 4 Jun 16:39 corda-rpcProxy.jar
-rw-r--r-- 1 user staff 66441262 4 Jun 16:38 corda.jar
-rw-r--r-- 1 user staff 71987460 4 Jun 16:39 dbmigration.jar
-rw-r--r-- 1 user staff 112985324 4 Jun 16:39 network-bootstrapper.jar
-rwxr-xr-x 1 user staff 1224 4 Jun 16:39 startRPCproxy.sh
/Users/home/staging/corda/r3corda-master/apps:
total 82248
-rw------- 1 user staff 2418144 4 Jun 16:38 corda-finance-R3.CORDA-3.0-SNAPSHOT.jar
```
Notes:
- all versions of Corda published to the Artifactory release repositories are automatically downloaded and configured
on the fly as part of a test scenario.
- Docker must be running for SQL Server, Oracle and PostrgeSQL tests.
Usage
-----
Checkout the latest version of the Enterprise repo and run:
```bash
$cd experimental/behave
../../gradlew behaveJar
````
Change to the QA testing directory containing the scenario scripts and run:
```bash
$cd ../../test/qa
$export BEHAVE_JAR=$(ls ../../../experimental/behave/build/libs/corda-behave-*.jar | tail -n1)
```
To verify the tool is ready to be used run:
```bash
$ java -DSTAGING_ROOT=${STAGING_ROOT} -jar ${BEHAVE_JAR}
```
You should now see the following output providing details on how to run the tool:
```bash
Missing required option(s) [path]
Usage: ScenarioRunner [options] --path <location of feature scenario definitions>
Examples:
ScenarioRunner -path <features-dir>
ScenarioRunner -path <features-dir>/<name>.feature
ScenarioRunner -path <features-dir>/<name>.feature:3:9
ScenarioRunner -path <features-dir> --plugin html --tags @qa
ScenarioRunner -path <features-dir> --plugin html --tags @compatibility
Please refer to the Cucumber documentation https://cucumber.io/docs/reference/jvm for more info.
Option (* = required) Description
--------------------- -----------
-d
--glue [location of additional step (default: net.corda.behave.scenarios)
definitions, hooks and plugins]
* --path <Path location of .feature
specifications>
--plugin [register additional plugins (default: pretty)
(see https://cucumber.
io/docs/reference/jvm)]
--tags [only run scenarios marked as
@<tag-name>]
```
Note: passing in a *-d* option will perform a dry run only (validates the syntax of the scenario but does not execute the code)
Scenario scripts
----------------
There are currently two sets of scripts:
1. Functional
```bash
# the Cucumber behave test scenario definitions themselves
$ls -l functional/resources/features/functional.feature
# Unix script to easily run these
$ls -l functional/resources/scripts/run-functional.sh
```
2. Interoperability & Compatibility
```bash
# the Cucumber behave test scenario definitions themselves
$ls -l compatibility/resources/features/interoperability.feature
# Unix script to easily run these
$ls -l compatibility/resources/scripts/run-interoperability.sh
```
Note: the complete suite of Compatibility test scenarios have note yet been fully implemented.
You can now run the above test scripts in a number of different ways:
* as a complete suite called a *feature set*:
```bash
# run all scenarios in the functional.feature file
$java -DSTAGING_ROOT=${STAGING_ROOT} -jar ${BEHAVE_JAR} -path functional/resources/features/functional.feature
```
```bash
# run all scenarios in the interoperability.feature file
$java -DSTAGING_ROOT=${STAGING_ROOT} -jar ${BEHAVE_JAR} -path compatibility/resources/features/interoperability.feature
```
* as a set of tagged scenarios within a feature file:
```bash
# run all scenarios tagged with qa in the interoperability.feature file
$java -DSTAGING_ROOT=${STAGING_ROOT} -jar ${BEHAVE_JAR} -path compatibility/resources/features/interoperability.feature:@qa
```
* as an individual scenario for all example configurations:
```bash
# run the scenario defined on line 5 of the interoperability.feature file
$java -DSTAGING_ROOT=${STAGING_ROOT} -jar ${BEHAVE_JAR} -path compatibility/resources/features/interoperability.feature:5
# by default the above will run as many times as there are parameterised variable definitions
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 |
```
* as an individual scenario for a single example configuration you will need to comment out the other example line items:
```bash
# run the scenario defined on line 5 of the interoperability.feature file
$java -DSTAGING_ROOT=${STAGING_ROOT} -jar ${BEHAVE_JAR} -path compatibility/resources/features/interoperability.feature:5
# by default the above will the scenario using *corda-3.0* and *corda-3.1* node versions only:
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 |
```

View File

@ -12,5 +12,8 @@ BEHAVE_DIR=${R3CORDA_HOME}/experimental/behave
cd ${BEHAVE_DIR}
../../gradlew behaveJar
# QA interoperability
java -jar ${BEHAVE_DIR}/build/libs/corda-behave.jar -d --glue net.corda.behave.scenarios -path ${R3CORDA_HOME}/testing/qa/behave/compatibility/resources/features/interoperability.feature
BEHAVE_JAR=$(ls build/libs/corda-behave-*.jar | tail -n1)
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

View File

@ -7,12 +7,12 @@ Feature: QA Operational
And node PartyA has the finance app installed
When the network is ready
Then node PartyA is on platform version 4
And node PartyA is on release version R3.CORDA-3.0.0-DEV-PREVIEW-3
And node PartyA is on release version <Version-label>
And user can retrieve node identity information for node PartyA
Examples:
| R3-Corda-Node-Version |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 |
| R3-Corda-Node-Version | Version-label |
| 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
@ -22,8 +22,8 @@ Feature: QA Operational
Then node PartyA can issue 1000 <Currency>
Examples:
| R3-Corda-Node-Version | Currency |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | GBP |
| R3-Corda-Node-Version | Currency |
| r3-master | GBP |
Scenario Outline: User can connect to a Corda Enterprise node using a SQL Server database
Given a node PartyA of version <Node-Version>
@ -32,8 +32,8 @@ Feature: QA Operational
Then user can connect to the database of node PartyA
Examples:
| Node-Version | Database-Type |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | SQL Server |
| Node-Version | Database-Type |
| 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
@ -47,8 +47,8 @@ Feature: QA Operational
And node PartyA can transfer 100 <Currency> to node B
Examples:
| R3-Corda-Node-Version | Currency | Database-Type |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | GBP | SQL Server |
| R3-Corda-Node-Version | Currency | Database-Type |
| r3-master | GBP | SQL Server |
Scenario Outline: User can connect to a Corda Enterprise node using a PostgreSQL database
Given a node PartyA of version <Node-Version>
@ -57,8 +57,8 @@ Feature: QA Operational
Then user can connect to the database of node PartyA
Examples:
| Node-Version | Database-Type |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | postgres |
| Node-Version | Database-Type |
| 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
@ -72,5 +72,5 @@ Feature: QA Operational
And node PartyA can transfer 100 <Currency> to node B
Examples:
| R3-Corda-Node-Version | Currency | Database-Type |
| R3.CORDA-3.0.0-DEV-PREVIEW-3 | GBP | postgres |
| R3-Corda-Node-Version | Currency | Database-Type |
| r3-master | GBP | postgres |

View File

@ -1,11 +1,11 @@
#!/bin/bash
#
# Run this script from your ${R3CORDA_HOME}/experimental/behave directory, where R3CORDA_HOME refers to Corda Enterprise source code (eg. GitHub master, branch or TAG)
# Run this script from your $R3CORDA_HOME directory, where R3CORDA_HOME refers to R3 Corda source code (eg. GitHub master, branch or TAG)
# For example:
# R3CORDA_HOME => git clone https://github.com/corda/enterprise
#
# $ testing/qa/behave/compatibility/resources/scripts/run-functional.sh
# $ testing/qa/behave/functional/resources/scripts/run-functional.sh
R3CORDA_HOME=$PWD
@ -13,5 +13,8 @@ BEHAVE_DIR=${R3CORDA_HOME}/experimental/behave
cd ${BEHAVE_DIR}
../../gradlew behaveJar
# QA functional
java -jar ${BEHAVE_DIR}/build/libs/corda-behave.jar -d --glue net.corda.behave.scenarios -path ${R3CORDA_HOME}/testing/qa/behave/functional/resources/features/functional.feature
BEHAVE_JAR=$(ls build/libs/corda-behave-*.jar | tail -n1)
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

View File

@ -12,7 +12,11 @@
VERSION=master
BUILD_DIR=`pwd`
STAGING_DIR=~/staging/corda/corda-${VERSION}
STAGING_DIR="${STAGING_ROOT:-$TMPDIR/staging}"
echo "Staging directory: $STAGING_DIR"
CORDA_DIR=${STAGING_DIR}/corda/corda-${VERSION}
echo "Corda staging directory: $CORDA_DIR"
# Set up directories
mkdir -p ${STAGING_DIR}/apps
@ -21,19 +25,19 @@ cd ${BUILD_DIR}
echo "*************************************************************"
echo "Building and installing $VERSION from $BUILD_DIR"
echo " to $STAGING_DIR"
echo " to $CORDA_DIR"
echo "*************************************************************"
# Copy Corda capsule into deps
./gradlew clean install
cp -v $(ls node/capsule/build/libs/corda-*.jar | tail -n1) ${STAGING_DIR}/corda.jar
cp -v $(ls finance/build/libs/corda-finance-*.jar | tail -n1) ${STAGING_DIR}/apps
cp -v $(ls node/capsule/build/libs/corda-*.jar | tail -n1) ${CORDA_DIR}/corda.jar
cp -v $(ls finance/build/libs/corda-finance-*.jar | tail -n1) ${CORDA_DIR}/apps
# Build Network Bootstrapper
./gradlew buildBootstrapperJar
cp -v $(ls tools/bootstrapper/build/libs/*.jar | tail -n1) ${STAGING_DIR}/network-bootstrapper.jar
cp -v $(ls tools/bootstrapper/build/libs/*.jar | tail -n1) ${CORDA_DIR}/network-bootstrapper.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
cp -v $(ls testing/qa/behave/tools/rpc-proxy/build/libs/corda-rpcProxy*.jar | tail -n1) ${STAGING_DIR}/corda-rpcProxy.jar
cp -v testing/qa/behave/tools/rpc-proxy/startRPCproxy.sh ${STAGING_DIR}
cp -v $(ls testing/qa/behave/tools/rpc-proxy/build/libs/corda-rpcProxy*.jar | tail -n1) ${CORDA_DIR}/corda-rpcProxy.jar
cp -v testing/qa/behave/tools/rpc-proxy/startRPCproxy.sh ${CORDA_DIR}