From c2f22e18a535af82a3a254c021207f9c8a63371d Mon Sep 17 00:00:00 2001 From: josecoll Date: Tue, 5 Jun 2018 15:02:07 +0100 Subject: [PATCH] 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. --- experimental/behave/README.md | 33 ++- experimental/behave/prepare.sh | 30 ++- .../SqlServerConfigurationTemplate.kt | 2 +- .../net/corda/behave/network/Network.kt | 39 ++-- .../net/corda/behave/node/Distribution.kt | 85 ++++++-- .../main/kotlin/net/corda/behave/node/Node.kt | 20 +- .../node/configuration/Configuration.kt | 2 +- .../net/corda/behave/process/Command.kt | 2 +- .../network-parameters-without-notary.conf | 1 + .../resources/doorman/network-parameters.conf | 1 + .../behave/scenarios/helpers/Substeps.kt | 4 +- .../resources/scripts/run-behave-features.sh | 2 +- .../net/corda/behave/node/DistributionTest.kt | 34 +++ testing/qa/behave/README.md | 198 +++++++++++++++++- .../resources/scripts/run-interoperability.sh | 7 +- .../resources/features/functional.feature | 26 +-- .../resources/scripts/run-functional.sh | 11 +- testing/qa/behave/scripts/update-corda-cts.sh | 18 +- 18 files changed, 435 insertions(+), 80 deletions(-) create mode 100644 experimental/behave/src/test/kotlin/net/corda/behave/node/DistributionTest.kt diff --git a/experimental/behave/README.md b/experimental/behave/README.md index 9f5d32a2d2..d0f7a1c838 100644 --- a/experimental/behave/README.md +++ b/experimental/behave/README.md @@ -55,4 +55,35 @@ the following parameter to the Gradle command: $ ../../gradlew scenario -Ptags="@cash" # or $ ../../gradlew scenario -Ptags="@cash,@logging" -``` \ No newline at end of file +``` + +# 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 +``` diff --git a/experimental/behave/prepare.sh b/experimental/behave/prepare.sh index 1827506bde..2ab409b448 100755 --- a/experimental/behave/prepare.sh +++ b/experimental/behave/prepare.sh @@ -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} + diff --git a/experimental/behave/src/main/kotlin/net/corda/behave/database/configuration/SqlServerConfigurationTemplate.kt b/experimental/behave/src/main/kotlin/net/corda/behave/database/configuration/SqlServerConfigurationTemplate.kt index 6b544c632e..10b8be34f8 100644 --- a/experimental/behave/src/main/kotlin/net/corda/behave/database/configuration/SqlServerConfigurationTemplate.kt +++ b/experimental/behave/src/main/kotlin/net/corda/behave/database/configuration/SqlServerConfigurationTemplate.kt @@ -28,7 +28,7 @@ class SqlServerConfigurationTemplate : DatabaseConfigurationTemplate() { | dataSource.password = "${it.password}" |} |database = { - | initialiseSchema=true + | runMigration=true | transactionIsolationLevel = READ_COMMITTED | schema="${it.schema}" |} diff --git a/experimental/behave/src/main/kotlin/net/corda/behave/network/Network.kt b/experimental/behave/src/main/kotlin/net/corda/behave/network/Network.kt index d853694ce8..0946c70fdd 100644 --- a/experimental/behave/src/main/kotlin/net/corda/behave/network/Network.kt +++ b/experimental/behave/src/main/kotlin/net/corda/behave/network/Network.kt @@ -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-.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-.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 ...") } } diff --git a/experimental/behave/src/main/kotlin/net/corda/behave/node/Distribution.kt b/experimental/behave/src/main/kotlin/net/corda/behave/node/Distribution.kt index c5284aa434..2d9ca68264 100644 --- a/experimental/behave/src/main/kotlin/net/corda/behave/node/Distribution.kt +++ b/experimental/behave/src/main/kotlin/net/corda/behave/node/Distribution.kt @@ -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? = 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) { + 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, version: String, artifactoryBaseUrl: String) : Map { + val urlMap = mutableMapOf() + 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") + } } } } diff --git a/experimental/behave/src/main/kotlin/net/corda/behave/node/Node.kt b/experimental/behave/src/main/kotlin/net/corda/behave/node/Node.kt index a222e7c7c3..8d48eb85f2 100644 --- a/experimental/behave/src/main/kotlin/net/corda/behave/node/Node.kt +++ b/experimental/behave/src/main/kotlin/net/corda/behave/node/Node.kt @@ -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( diff --git a/experimental/behave/src/main/kotlin/net/corda/behave/node/configuration/Configuration.kt b/experimental/behave/src/main/kotlin/net/corda/behave/node/configuration/Configuration.kt index 3f5a8c3199..3986960a4d 100644 --- a/experimental/behave/src/main/kotlin/net/corda/behave/node/configuration/Configuration.kt +++ b/experimental/behave/src/main/kotlin/net/corda/behave/node/configuration/Configuration.kt @@ -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) diff --git a/experimental/behave/src/main/kotlin/net/corda/behave/process/Command.kt b/experimental/behave/src/main/kotlin/net/corda/behave/process/Command.kt index cbfb289c79..72818f5f42 100644 --- a/experimental/behave/src/main/kotlin/net/corda/behave/process/Command.kt +++ b/experimental/behave/src/main/kotlin/net/corda/behave/process/Command.kt @@ -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) diff --git a/experimental/behave/src/main/resources/doorman/network-parameters-without-notary.conf b/experimental/behave/src/main/resources/doorman/network-parameters-without-notary.conf index 1f47b7f021..1aedee3b44 100644 --- a/experimental/behave/src/main/resources/doorman/network-parameters-without-notary.conf +++ b/experimental/behave/src/main/resources/doorman/network-parameters-without-notary.conf @@ -1,3 +1,4 @@ minimumPlatformVersion = 1 maxMessageSize = 10485760 maxTransactionSize = 10485760 +eventHorizonDays = 30 diff --git a/experimental/behave/src/main/resources/doorman/network-parameters.conf b/experimental/behave/src/main/resources/doorman/network-parameters.conf index a34049e6cb..1315d40f2d 100644 --- a/experimental/behave/src/main/resources/doorman/network-parameters.conf +++ b/experimental/behave/src/main/resources/doorman/network-parameters.conf @@ -5,3 +5,4 @@ notaries : [{ minimumPlatformVersion = 1 maxMessageSize = 10485760 maxTransactionSize = 10485760 + eventHorizonDays = 30 diff --git a/experimental/behave/src/scenario/kotlin/net/corda/behave/scenarios/helpers/Substeps.kt b/experimental/behave/src/scenario/kotlin/net/corda/behave/scenarios/helpers/Substeps.kt index 1fa04e4d4f..d2168d6f0d 100644 --- a/experimental/behave/src/scenario/kotlin/net/corda/behave/scenarios/helpers/Substeps.kt +++ b/experimental/behave/src/scenario/kotlin/net/corda/behave/scenarios/helpers/Substeps.kt @@ -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() protected fun withNetwork(action: ScenarioState.() -> Unit) = state.withNetwork(action) diff --git a/experimental/behave/src/scenario/resources/scripts/run-behave-features.sh b/experimental/behave/src/scenario/resources/scripts/run-behave-features.sh index 86220635d4..ef253191fa 100755 --- a/experimental/behave/src/scenario/resources/scripts/run-behave-features.sh +++ b/experimental/behave/src/scenario/resources/scripts/run-behave-features.sh @@ -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 diff --git a/experimental/behave/src/test/kotlin/net/corda/behave/node/DistributionTest.kt b/experimental/behave/src/test/kotlin/net/corda/behave/node/DistributionTest.kt new file mode 100644 index 0000000000..736c77cfa8 --- /dev/null +++ b/experimental/behave/src/test/kotlin/net/corda/behave/node/DistributionTest.kt @@ -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}") + } +} \ No newline at end of file diff --git a/testing/qa/behave/README.md b/testing/qa/behave/README.md index 863d21d1f7..f2cbecaac2 100644 --- a/testing/qa/behave/README.md +++ b/testing/qa/behave/README.md @@ -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) \ No newline at end of file + 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 + +Examples: + ScenarioRunner -path + ScenarioRunner -path /.feature + ScenarioRunner -path /.feature:3:9 + + ScenarioRunner -path --plugin html --tags @qa + ScenarioRunner -path --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 +--plugin [register additional plugins (default: pretty) + (see https://cucumber. + io/docs/reference/jvm)] +--tags [only run scenarios marked as + @] +``` +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 | +``` diff --git a/testing/qa/behave/compatibility/resources/scripts/run-interoperability.sh b/testing/qa/behave/compatibility/resources/scripts/run-interoperability.sh index 894e863694..51b9238886 100755 --- a/testing/qa/behave/compatibility/resources/scripts/run-interoperability.sh +++ b/testing/qa/behave/compatibility/resources/scripts/run-interoperability.sh @@ -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 diff --git a/testing/qa/behave/functional/resources/features/functional.feature b/testing/qa/behave/functional/resources/features/functional.feature index 0efac9051d..4086956601 100644 --- a/testing/qa/behave/functional/resources/features/functional.feature +++ b/testing/qa/behave/functional/resources/features/functional.feature @@ -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 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 with proxy @@ -22,8 +22,8 @@ Feature: QA Operational Then node PartyA can issue 1000 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 @@ -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 with proxy @@ -47,8 +47,8 @@ Feature: QA Operational And node PartyA can transfer 100 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 @@ -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 with proxy @@ -72,5 +72,5 @@ Feature: QA Operational And node PartyA can transfer 100 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 | diff --git a/testing/qa/behave/functional/resources/scripts/run-functional.sh b/testing/qa/behave/functional/resources/scripts/run-functional.sh index 2b741985cd..0dc494af1a 100755 --- a/testing/qa/behave/functional/resources/scripts/run-functional.sh +++ b/testing/qa/behave/functional/resources/scripts/run-functional.sh @@ -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 \ No newline at end of file diff --git a/testing/qa/behave/scripts/update-corda-cts.sh b/testing/qa/behave/scripts/update-corda-cts.sh index 5189f3ea4e..e8b3cacbe2 100755 --- a/testing/qa/behave/scripts/update-corda-cts.sh +++ b/testing/qa/behave/scripts/update-corda-cts.sh @@ -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} \ No newline at end of file +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} \ No newline at end of file