diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index be559623b4fdc534be7efd095ef6529ff1037bf6..0b2d0b1fda3cfffba046eee39466bcb5df033b5b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -44,7 +44,7 @@ build:jar: script: - mkdir -p cordapps/build # compile and package - - (cd cordapps && ./gradlew clean checkLicense build -x test --parallel --info -PpipelineId=${CI_PIPELINE_ID}) + - (cd cordapps && ./gradlew clean checkLicense build -x test --parallel --info -PpipelineId=${CI_PIPELINE_ID}) # tests # - (cd cordapps && ./gradlew build -x :checkLicense --info) ?? isn't this the same as above?! # build Node layout @@ -57,10 +57,10 @@ build:jar: artifacts: name: "cordite-build-$CI_PIPELINE_ID" paths: - - node/* - - cordapps/build/gradle.log + - node/* + - cordapps/build/gradle.log except: - - 658-refactor-cordite-docker-implementation-to-use-official-corda-image + - 658-refactor-cordite-docker-implementation-to-use-official-corda-image # code_quality: # stage: build @@ -84,19 +84,19 @@ build:jar: # - docker build:pages: - image: cordite/rtd:latest - stage: build - script: - - cd docs - - make clean - - make html - tags: + image: cordite/rtd:latest + stage: build + script: + - cd docs + - make clean + - make html + tags: - kubernetes - except: - - master - - 678-upgrade-to-corda-4-x - - /v[0-9]+\.[0-9]+\.[0-9]+/ - allow_failure: true + except: + - master + - 678-upgrade-to-corda-4-x + - /v[0-9]+\.[0-9]+\.[0-9]+/ + allow_failure: true build:node-client: image: node:latest @@ -115,26 +115,24 @@ build:node-client: - kubernetes allow_failure: true -test:nms: +test:regression: stage: test image: dazraf/build-tools:latest - services: - - docker:18.09-dind - variables: - DOCKER_HOST: tcp://docker:2375/ - DOCKER_DRIVER: overlay2 before_script: + - echo "registry ${CI_REGISTRY}" + - echo "${CI_REGISTRY_IMAGE}" - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY + - docker pull ${CI_REGISTRY_IMAGE}:${CI_PIPELINE_ID} - docker info retry: 2 script: - date - docker pull cordite/network-map:latest - date - - cd test && ./test-nms.sh ${CI_REGISTRY_IMAGE}:${CI_PIPELINE_ID} docker-test + - cd test/regression && ./run.sh cordite/cordite:v0.4.10 ${CI_REGISTRY_IMAGE}:${CI_PIPELINE_ID} min - date tags: - - kubernetes + - build-tools dependencies: [] except: - 291-integration-with-other-ledgers-and-payment-rails @@ -169,7 +167,7 @@ test:nms: # - /v[0-9]+\.[0-9]+\.[0-9]+/ # - 599-bosh-over-to-push-deployments-to-eke # - 678-upgrade-to-corda-4-xx -# tags: +# tags: # - docker # dependencies: [] # tags: @@ -196,7 +194,7 @@ test:nms: # paths: [gl-sast-report.json] # except: # - /v[0-9]+\.[0-9]+\.[0-9]+/ -# tags: +# tags: # - docker # dependencies: [] @@ -210,7 +208,7 @@ dependency_scanning: artifacts: reports: dependency_scanning: gl-dependency-check-report.json - tags: + tags: - docker only: - master @@ -249,32 +247,32 @@ release:node-client: only: - /v[0-9]+\.[0-9]+\.[0-9]+/ dependencies: [] - tags: + tags: - docker allow_failure: true release:pages: - image: cordite/rtd:latest - stage: release - script: - - date - - cd docs - - make clean - - make html - - mv _build/html/ ../public/ - - echo "documentation built here on master build https://cordite.gitlab.io/cordite/" - - echo "RTD will build automatically here on tagged CIs http://cordite.readthedocs.io/en/latest/" - - date - tags: + image: cordite/rtd:latest + stage: release + script: + - date + - cd docs + - make clean + - make html + - mv _build/html/ ../public/ + - echo "documentation built here on master build https://cordite.gitlab.io/cordite/" + - echo "RTD will build automatically here on tagged CIs http://cordite.readthedocs.io/en/latest/" + - date + tags: - docker - artifacts: - paths: - - public - only: - - master - - /v[0-9]+\.[0-9]+\.[0-9]+/ - allow_failure: true - dependencies: [] + artifacts: + paths: + - public + only: + - master + - /v[0-9]+\.[0-9]+\.[0-9]+/ + allow_failure: true + dependencies: [] release:gitlab-docker: image: docker:latest @@ -292,10 +290,11 @@ release:gitlab-docker: only: - master - /v[0-9]+\.[0-9]+\.[0-9]+/ + - 705-upgrade-to-corda-4-4 dependencies: [] deploy:edge: - image: + image: name: nimmaj/cordite-gcloud-alpine:latest stage: deploy script: @@ -308,8 +307,9 @@ deploy:edge: - ./etc/deploy/upgradeGkeEnv.sh ${CI_PIPELINE_ID} ${GCLOUD_ENV} tags: - kubernetes - only: + only: - master + - 705-upgrade-to-corda-4-4 dependencies: - build:jar @@ -326,6 +326,7 @@ int-test:edge: - docker only: - master + - 705-upgrade-to-corda-4-4 dependencies: - build:jar @@ -345,7 +346,7 @@ dast: only: - master - 678-upgrade-to-corda-4-x - tags: + tags: - docker dependencies: [] @@ -362,7 +363,7 @@ edge-release-docker: - docker tag ${CI_REGISTRY_IMAGE}:${CI_PIPELINE_ID} ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG:-edge} ; docker push ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG:-edge} - docker login -u "${DOCKER_HUB_USER}" -p "${DOCKER_HUB_PASSWORD}" - docker tag ${CI_REGISTRY_IMAGE}:${CI_PIPELINE_ID} cordite/cordite:edge ; docker push cordite/cordite:edge - - SLACK_MESSAGE="New cordite docker image with tag edge released on hub.docker.com/r/cordite/cordite/ by gitlab.com/cordite/cordite/pipelines/${CI_PIPELINE_ID} from gitlab.com/cordite/cordite/commit/${CI_COMMIT_SHA} ; Tested on https://network-map-edge.cordite.foundation" + - SLACK_MESSAGE="New cordite docker image with tag edge released on hub.docker.com/r/cordite/cordite/ by gitlab.com/cordite/cordite/pipelines/${CI_PIPELINE_ID} from gitlab.com/cordite/cordite/commit/${CI_COMMIT_SHA} ; Tested on https://network-map-edge.cordite.foundation" - SLACK_PAYLOAD={\"text\":\"${SLACK_MESSAGE}\"} - wget -O- --post-data="${SLACK_PAYLOAD}" --header=Content-Type:application/json "https://hooks.slack.com/services/${SLACK_TOKEN}" - date @@ -373,7 +374,7 @@ edge-release-docker: dependencies: [] deploy:test: - image: + image: name: nimmaj/cordite-gcloud-alpine:latest stage: deploy script: @@ -386,9 +387,9 @@ deploy:test: - ./etc/deploy/upgradeGkeEnv.sh ${CI_PIPELINE_ID} test tags: - docker - only: + only: - /v[0-9]+\.[0-9]+\.[0-9]+/ - dependencies: + dependencies: - build:jar int-test:test: @@ -404,7 +405,7 @@ int-test:test: - docker only: - /v[0-9]+\.[0-9]+\.[0-9]+/ - dependencies: + dependencies: - build:jar test-release-docker: @@ -431,7 +432,6 @@ test-release-docker: - /v[0-9]+\.[0-9]+\.[0-9]+/ - 599-bosh-over-to-push-deployments-to-eke dependencies: [] - # the following should be removed when corda-4 branch has successfully upgraded dao and metering # corda-4-release-docker: # image: docker:latest @@ -472,4 +472,4 @@ test-release-docker: # - build-tools # only: # - 678-upgrade-to-corda-4-x -# dependencies: [] \ No newline at end of file +# dependencies: [] diff --git a/clients/cli/README.md b/clients/cli/README.md index 2bf5e26f0aa04c18fde89c7207b0448837ba0fa5..8d81fc889756ca645cc6a67dd22bf38ea733ba72 100644 --- a/clients/cli/README.md +++ b/clients/cli/README.md @@ -15,6 +15,7 @@ limitations under the License. --> + # Cordite CLI ![cordite console in action](output.gif) @@ -24,6 +25,7 @@ - [Cordite CLI](#cordite-cli) - [Contents](#contents) - [Build](#build) +- [Parameters](#parameters) - [Startup](#startup) - [Shutdown](#shutdown) - [API](#api) @@ -52,6 +54,31 @@ To clean the output: npm run clean ``` +# Parameters + +The parameters can be listed using `cordite --help`. + +``` +node cordite.js --help + +Cordite + + Client to connect to braid-enabled Corda nodes + +Options + + --help print this usage guide + -u, --url string connection ://: + -s, --strictSSL enable or disable strict SSL checks + -c, --credentials string credentials payload + -f, --script string script file to be executed + +example: + cordite https://myhost.com:8081 --credentials '{ "username": "admin", "password": "admin"}' --strictSSL +``` + +The url can be passed as the only non-flagged parameter. + # Startup Assuming you are in the directory with the binary for your OS @@ -60,6 +87,28 @@ Assuming you are in the directory with the binary for your OS ./cordite https://apac-test.cordite.foundation ``` +You can also run the cordite client in a non-interactive mode by passing in a reference to a script file using the `-f` flag. + +``` +cordite -f myscript.js http://localhost:8083 +``` + +The script can use ES6 async/await calls. + +Here's an example of a script: + +```javascript +console.log(notaries); +const notary = notaries.notaryService.name; +try { + await ledger.createAccount("fuzz", notary); +} catch (err) { + console.log(err.message); +} +const accounts = await ledger.listAccounts(); +console.log(`accounts: ${JSON.stringify(accounts, null, 2)}`); +``` + # Shutdown Either type `.exit` or press `ctrl-c` twice. @@ -70,12 +119,12 @@ The CLI automatically creates top-level constants for each of the services avail The following constants are presently available: -* `corda` - top-level proxy to the corda node -* `ledger` - the asset ledger -* `dao` - the service for managing decentralised autonomous organistaions -* `metering` - the service responsible for metering of transactions -* `network` - the Corda network -* `flows` - access to the raw Corda flows framework +- `corda` - top-level proxy to the corda node +- `ledger` - the asset ledger +- `dao` - the service for managing decentralised autonomous organistaions +- `metering` - the service responsible for metering of transactions +- `network` - the Corda network +- `flows` - access to the raw Corda flows framework You can discover what methods are available on each by typing the constant name and pressing enter. @@ -87,18 +136,18 @@ e.g. # Record a Demo -* [Install](https://asciinema.org/docs/installation) Asciinema -* [Install](https://github.com/asciinema/asciicast2gif) AsciiCast2Gif (suggest `npm install -g asciicast2gif`) -* Ensure you have an up-to-date version of `screen` (e.g. `brew install screen`) -* Startup a server somewhere. This guide assumes you have started this using `io/cordite/SimpleStandaloneNetwork.kt` -* Open a terminal window. Make sure it is going to be large enough for your demo. Resizing mid-demo is _not_ recommended! -* Run: `asciinema rec ~/tmp/recording.json` -* Either: - * Single node: `./target/osx-x64/cordite []` - * Multi node: `screen -c cordite-screen.rc` - * To tab between each screen-split using `ctrl-a ` -* When done with your demo, exit from `cordite` using either `ctrl-c ctrl-c` or entering the `.exit` command -* Press `ctrl-d` to finish the `asciinema` recording -* Generate the gif using: `asciicast2gif -t solarized-light ~/tmp/recording.json ~/tmp/output.gif` -* Publish your gif here: `https://gitlab.com/cordite/cordite/wikis/cli-demos` -* Broadcast the gif to your network and become famous! \ No newline at end of file +- [Install](https://asciinema.org/docs/installation) Asciinema +- [Install](https://github.com/asciinema/asciicast2gif) AsciiCast2Gif (suggest `npm install -g asciicast2gif`) +- Ensure you have an up-to-date version of `screen` (e.g. `brew install screen`) +- Startup a server somewhere. This guide assumes you have started this using `io/cordite/SimpleStandaloneNetwork.kt` +- Open a terminal window. Make sure it is going to be large enough for your demo. Resizing mid-demo is _not_ recommended! +- Run: `asciinema rec ~/tmp/recording.json` +- Either: + - Single node: `./target/osx-x64/cordite []` + - Multi node: `screen -c cordite-screen.rc` + - To tab between each screen-split using `ctrl-a ` +- When done with your demo, exit from `cordite` using either `ctrl-c ctrl-c` or entering the `.exit` command +- Press `ctrl-d` to finish the `asciinema` recording +- Generate the gif using: `asciicast2gif -t solarized-light ~/tmp/recording.json ~/tmp/output.gif` +- Publish your gif here: `https://gitlab.com/cordite/cordite/wikis/cli-demos` +- Broadcast the gif to your network and become famous! diff --git a/clients/cli/cordite.js b/clients/cli/cordite.js index 01988d2b599ac2e41b45160cd1188ba3fd52d416..11aa15250889dc6fe6a9c0127207f97986618c57 100755 --- a/clients/cli/cordite.js +++ b/clients/cli/cordite.js @@ -14,19 +14,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const os = require('os'); -const repl = require('repl'); -const fs = require('fs'); -const Proxy = require('braid-client').Proxy; -const deepromisify = require('./deepromise-repl'); -const historyPath = os.homedir() + '/.cordite_repl_history' -const commandLineArgs = require('command-line-args') -const commandLineUsage = require('command-line-usage') +const os = require("os"); +const repl = require("repl"); +const fs = require("fs"); +const Proxy = require("braid-client").Proxy; +const deepromisify = require("./deepromise-repl"); +const historyPath = os.homedir() + "/.cordite_repl_history"; +const commandLineArgs = require("command-line-args"); +const commandLineUsage = require("command-line-usage"); +const rewrite = require("./deepromise"); const corditeBanner = ` _____ ___ __ / ___/__ _______/ (_) /____ / /__/ _ \\/ __/ _ / / __/ -_) -\\___/\\___/_/ \\_,_/_/\\__/\\__/` +\\___/\\___/_/ \\_,_/_/\\__/\\__/`; var corda = null; const notaries = {}; @@ -34,30 +35,57 @@ const globalSymbolNames = []; const sections = [ { - header: 'Cordite', - content: 'Client to connect to braid-enabled Corda nodes' + header: "Cordite", + content: "Client to connect to braid-enabled Corda nodes", }, { - header: 'Options', + header: "Options", optionList: [ - { name: 'help', description: 'print this usage guide' }, - { name: 'url', description: 'connection ://:', alias: 'u', type: String, defaultOption: true, defaultValue: 'https://localhost:8081' }, - { name: 'strictSSL', description: 'enable or disable strict SSL checks', alias: 's', type: Boolean, defaultValue: false }, - { name: 'credentials', description: 'credentials payload', alias: 'v', type: String, alias: 'c', defaultValue: "" } - ] - } -] - + { name: "help", description: "print this usage guide" }, + { + name: "url", + description: "connection ://:", + alias: "u", + type: String, + defaultOption: true, + defaultValue: "https://localhost:8081", + }, + { + name: "strictSSL", + description: "enable or disable strict SSL checks", + alias: "s", + type: Boolean, + defaultValue: false, + }, + { + name: "credentials", + description: "credentials payload", + type: String, + alias: "c", + defaultValue: "", + }, + { + name: "script", + description: "script file to be executed", + type: String, + alias: "f", + defaultValue: "", + }, + ], + }, +]; function printBanner() { - console.log(''); + console.log(""); console.log(corditeBanner); } function printHelp() { console.log(commandLineUsage(sections)); - console.log('example:'); - console.log(' cordite https://myhost.com:8081 --credentials \'{ "username": "admin", "password": "admin"}\' --strictSSL'); + console.log("example:"); + console.log( + ' cordite https://myhost.com:8081 --credentials \'{ "username": "admin", "password": "admin"}\' --strictSSL' + ); } function run() { @@ -67,8 +95,8 @@ function run() { process.exit(); } const config = { - url: options.url + '/api/' - } + url: options.url + "/api/", + }; if (options.credentials) { config.credentials = JSON.parse(options.credentials); @@ -79,94 +107,147 @@ function run() { } const transportConfig = { - strictSSL: strictSSL + strictSSL: strictSSL, }; printBanner(); - console.log("connecting to", config.url, "with", config, "and", transportConfig); - corda = new Proxy(config, onOpen, onClose, onError, transportConfig); + console.log( + "connecting to", + config.url, + "with", + config, + "and", + transportConfig + ); + corda = new Proxy( + config, + () => { + onOpen(options); + }, + onClose, + onError, + transportConfig + ); } -function onOpen() { - printMyInfo() - .then(() => { - globalSymbolNames.push("corda", "notaries"); - Object.getOwnPropertyNames(corda).forEach(name => { - globalSymbolNames.push(name); - }); - console.log('available objects:', globalSymbolNames.join(', ')); +async function onOpen(options) { + await getAndProcessNotaries(); - replServer = repl.start({ - prompt: 'cordite > ', - }); + if (options.script) { + executeScript(options.script); + } else { + interactiveMode(); + } +} - replServer.context.corda = corda; - replServer.context.notaries = notaries; - Object.getOwnPropertyNames(corda).forEach(name => { - Object.defineProperty(replServer.context, name, { value: corda[name], writable: false }); - globalSymbolNames.push(name); - }); +function read(filename) { + return fs.readFileSync(filename, "utf-8"); +} + +async function executeScript(file) { + let script; + try { + script = fs.readFileSync(file, "utf8"); + const AsyncFunction = Object.getPrototypeOf(async function () {}) + .constructor; + const names = getPropertyNames(corda); + const values = getPropertyValues(corda); + const fn = new AsyncFunction("read", "corda", "notaries", ...names, script); + const result = await fn(read, corda, notaries, ...values); + console.log(result); + process.exit(); + } catch (err) { + console.error("failed to execute script: " + file); + console.error(err); + process.exit(-1); + } +} + +async function interactiveMode() { + try { + await printMyInfo(); + globalSymbolNames.push("corda", "notaries"); + Object.getOwnPropertyNames(corda).forEach((name) => { + globalSymbolNames.push(name); + }); + console.log("available objects:", globalSymbolNames.join(", ")); + + replServer = repl.start({ + prompt: "cordite > ", + }); - if (fs.existsSync(historyPath)) { - fs.statSync(historyPath); - fs.readFileSync(historyPath) - .toString() - .split('\n') - .reverse() - .filter(line => line.trim()) - .map(line => replServer.history.push(line)); - } - - replServer.on('exit', () => { - fs.appendFileSync(historyPath, replServer.lines.join('\n')); - process.exit(); + replServer.context.corda = corda; + replServer.context.notaries = notaries; + Object.getOwnPropertyNames(corda).forEach((name) => { + Object.defineProperty(replServer.context, name, { + value: corda[name], + writable: false, }); + globalSymbolNames.push(name); + }); + + if (fs.existsSync(historyPath)) { + fs.statSync(historyPath); + fs.readFileSync(historyPath) + .toString() + .split("\n") + .reverse() + .filter((line) => line.trim()) + .map((line) => replServer.history.push(line)); + } - deepromisify(replServer); - if (corda.network) { - return corda.network.notaryIdentities().then(n => { - processNotaries(n); - }); - }; - }) - .catch(err => { - console.error("failed during initialisation with error:", err); + replServer.on("exit", () => { + fs.appendFileSync(historyPath, replServer.lines.join("\n")); process.exit(); }); + + deepromisify(replServer); + } catch (err) { + console.error("failed during initialisation with error:", err); + process.exit(); + } } -function printMyInfo() { +async function printMyInfo() { if (corda.network) { - return corda.network.myNodeInfo() - .then(ni => { - console.log(''); - console.log('connected to node:', ni.legalIdentities[0].name) - console.log(''); - }); - }; + const ni = await corda.network.myNodeInfo(); + console.log(""); + console.log("connected to node:", ni.legalIdentities[0].name); + console.log(""); + } } function onError(e) { - console.error('could not connect', e); + console.error("could not connect", e); } function onClose() { - console.log('closed'); + console.log("closed"); +} + +async function getAndProcessNotaries() { + if (corda.network) { + const notaries = await corda.network.notaryIdentities(); + processNotaries(notaries); + } } function processNotaries(unparsedNotaries) { - const parsed = unparsedNotaries.map(n => { + const parsed = unparsedNotaries.map((n) => { const name = n.name; - const parsedName = name.split(',').map(i => i.trim()).map(i => i.split('=')) - .map(i => { + const parsedName = name + .split(",") + .map((i) => i.trim()) + .map((i) => i.split("=")) + .map((i) => { const o = {}; o[i[0]] = i[1]; return o; }) .reduce((acc, current) => { - return Object.assign(acc, current) - }, {}) - notaries[decapitalize(parsedName.O).split(' ').join('')] = n + return Object.assign(acc, current); + }, {}); + notaries[decapitalize(parsedName.O).split(" ").join("")] = n; }); } @@ -175,4 +256,14 @@ function decapitalize(str) { return str.charAt(0).toLowerCase() + str.substr(1); } +function getPropertyNames(obj) { + return Object.getOwnPropertyNames(obj); +} + +function getPropertyValues(obj) { + return getPropertyNames(obj).map((name) => { + return obj[name]; + }); +} + run(); diff --git a/clients/cli/example-script.js b/clients/cli/example-script.js new file mode 100644 index 0000000000000000000000000000000000000000..0a6e525c7a73d21b1ed398ad0732b4077589a91b --- /dev/null +++ b/clients/cli/example-script.js @@ -0,0 +1,24 @@ +/* + * Copyright 2018, Cordite Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +console.log(notaries); +const notary = notaries.notaryService.name; +try { + await ledger.createAccount("fuzz", notary); +} catch (err) { + console.log(err.message); +} +const accounts = await ledger.listAccounts(); +console.log(`accounts: ${JSON.stringify(accounts, null, 2)}`); diff --git a/clients/cli/package-lock.json b/clients/cli/package-lock.json index e242d22fccb67e0cfb1f56e5eab45eed13d2bdd4..21778db3abbbe41154ac7a8a19bf747718fe7fe0 100644 --- a/clients/cli/package-lock.json +++ b/clients/cli/package-lock.json @@ -1,6 +1,6 @@ { "name": "cordite-cli", - "version": "v0.3.7", + "version": "v0.3.10", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/test/regression/.gitignore b/test/regression/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/regression/README.md b/test/regression/README.md new file mode 100644 index 0000000000000000000000000000000000000000..990bc621871d2b66a364de20275e6a33d418e198 --- /dev/null +++ b/test/regression/README.md @@ -0,0 +1,30 @@ + + +# Regression Test + +The [`run.sh`](./run.sh) script takes two cordite docker images as parameters: the `baseline` and the `test` images. + +Defaults are: + +- `baseline`: `cordite/cordite:v0.4.10` +- `test`: `cordite/cordite:local` + +The script starts the `baseline`, persisting all state to docker volumes, and executes the first two scripts in the [scripts](./scripts) directory. + +Then it shutdown the network, and restarts it using the `test` image, and executes the remaining [scripts](./scripts). diff --git a/test/regression/build_env.sh b/test/regression/build_env.sh new file mode 100755 index 0000000000000000000000000000000000000000..abb4b180664f252e8a4c79a1998ff119af87fb81 --- /dev/null +++ b/test/regression/build_env.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# +# Copyright 2018, Cordite Foundation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# build environment +# usage ./build_env.sh + +IMAGE_TAG=${1:-cordite/cordite:local} +ENVIRONMENT_SLUG=${2:-min} + +if [ ${ENVIRONMENT_SLUG} = "min" ] +then + echo "starting a mini cordite network" + declare -a notaries=("bootstrap-notary") + declare -a nodes=("emea amer") + declare -a ports=("9082 9083") +else + echo "starting a full cordite network" + declare -a notaries=("bootstrap-notary") + declare -a nodes=("apac emea amer") + declare -a ports=("9081 9082 9083") +fi + +echo -e "\xE2\x9C\x94 $(date) create environment ${ENVIRONMENT_SLUG} with image tag ${IMAGE_TAG}" +set -e + +# clean up any old docker-compose containers and volumes +docker-compose -p ${ENVIRONMENT_SLUG} down --volumes --remove-orphans +docker volume prune -f + +# start NMS (and wait for it to be ready) +# docker login network-map +docker-compose -p ${ENVIRONMENT_SLUG} up -d network-map +until docker-compose -p ${ENVIRONMENT_SLUG} logs network-map | grep -q "io.cordite.networkmap.NetworkMapApp - started" +do + echo -e "waiting for network-map to start" + sleep 5 +done + +# start databasess +IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} up -d corda-db +until IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} logs corda-db | grep -q "database system is ready to accept connections" +do + echo -e "waiting for corda-db to start up and register..." + sleep 5 +done + +# start notaries (and wait for them to be ready) +# docker login cordite +for NOTARY in $notaries +do + IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} up -d ${NOTARY} +done +for NOTARY in $notaries +do + until IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} logs ${NOTARY} | grep -q "started up and registered" + do + echo -e "waiting for ${NOTARY} to start up and register..." + sleep 5 + done +done + +# Pause Notaries but not before downloading their NodeInfo-* and whitelist.txt +for NOTARY in $notaries +do + NODE_ID=$(docker-compose -p ${ENVIRONMENT_SLUG} ps -q ${NOTARY}) + NODEINFO=$(docker exec ${NODE_ID} ls | grep nodeInfo-) + docker cp ${NODE_ID}:/opt/cordite/${NODEINFO} ${NODEINFO} + docker exec ${NODE_ID} rm network-parameters + docker pause ${NODE_ID} +done + +# Register notaries with nms: +NMS_JWT=$(curl -X POST "http://localhost:9080/admin/api/login" -H "accept: text/plain" -H "Content-Type: application/json" -d "{ \"user\": \"admin\", \"password\": \"admin\"}") +echo "JWT: ${NMS_JWT}" + +for NODEINFO in nodeInfo-* +do + echo " registering ${NODEINFO}" + curl -X POST "http://localhost:9080/admin/api/notaries/nonValidating" -H "accept: text/plain" -H "Content-Type: application/octet-stream" -H "Authorization: Bearer ${NMS_JWT}" --data-binary "@${NODEINFO}" + rm ${NODEINFO} + echo -e "\xE2\x9C\x94 copied ${NODEINFO} to ${NMS_ID}" +done + +# re-start the notaries +for NOTARY in $notaries +do + IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} restart ${NOTARY} +done + + +# start regional nodes (and wait for them to be ready) +for NODE in $nodes +do + IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} up -d ${NODE} +done +for NODE in $nodes +do + until IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} logs ${NODE} | grep -q "started up and registered" + do + echo -e "waiting for ${NODE} to start up and register..." + sleep 5 + done +done + +# test endpoints +for PORT in $ports +do + while [[ "$(curl -sSfk -m 5 -o /dev/null -w ''%{http_code}'' https://localhost:${PORT}/api/)" != "200" ]] + do + echo -e "waiting for ${PORT} to return 200..." + sleep 5 + done +done + +echo -e "\xE2\x9C\x94 $(date) created environment ${ENVIRONMENT_SLUG} with image tag ${IMAGE_TAG}" \ No newline at end of file diff --git a/test/regression/cordite b/test/regression/cordite new file mode 100755 index 0000000000000000000000000000000000000000..9cdd9844e585af0757608d4daf195701e5774d78 --- /dev/null +++ b/test/regression/cordite @@ -0,0 +1,27 @@ +#!/bin/bash +# +# Copyright 2018, Cordite Foundation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# runs the cordite cli tool from anywhere +set -e +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd ) +echo $DIR +PROJECT_DIR=${DIR}/../../ +CLI_DIR=${PROJECT_DIR}/clients/cli +pushd ${CLI_DIR} +[[ -d node_modules ]] || npm install +popd +node ${CLI_DIR}/cordite.js $@ \ No newline at end of file diff --git a/test/regression/db-init/init-corda-db.sql b/test/regression/db-init/init-corda-db.sql new file mode 100644 index 0000000000000000000000000000000000000000..bc85d20eba01f70d6f970c572b46d8c26f016b8f --- /dev/null +++ b/test/regression/db-init/init-corda-db.sql @@ -0,0 +1,10 @@ +/** +The following sets up the databases required by each corda network in the docker-compose test cluster +*/ +CREATE DATABASE emea; +CREATE DATABASE amer; +CREATE DATABASE apac; +CREATE DATABASE metering; +CREATE DATABASE bootstrap; +CREATE DATABASE guardian; +CREATE DATABASE committee; diff --git a/test/regression/docker-compose.yml b/test/regression/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..95f1e23e8c7458158fb11a0d689c2d4d688d380d --- /dev/null +++ b/test/regression/docker-compose.yml @@ -0,0 +1,135 @@ +# +# Copyright 2018, Cordite Foundation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +version: "3.5" + +networks: + cordite: + +services: + corda-db: + image: postgres:10.5 + ports: + - "5432:5432" + volumes: + - ./db-init:/docker-entrypoint-initdb.d/ + - postgres_data:/var/lib/postgresql/data + networks: + cordite: + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 5 + network-map: + image: cordite/network-map:v0.5.0 + ports: + - "9080:9080" + volumes: + - nms:/opt/cordite/db + environment: + - NMS_PORT=9080 + - NMS_DB=/opt/cordite/db + - NMS_AUTH_USERNAME=admin + - NMS_AUTH_PASSWORD=admin + - NMS_TLS=false + - NMS_DOORMAN=false + - NMS_CERTMAN=false + - NMS_CACHE_TIMEOUT=10S + - NMS_STORAGE_TYPE=file + networks: + cordite: + bootstrap-notary: + image: ${IMAGE_TAG:-cordite/cordite:edge} + ports: + - "9087:8080" + volumes: + - bootstrap_certs:/opt/corda/certificates + - bootstrap_artemis:/opt/corda/artemis + - bootstrap_config:/etc/corda + environment: + - CORDITE_LEGAL_NAME=O=Cordite Bootstrap Notary, OU=Cordite Foundation, L=London,C=GB + - CORDITE_P2P_ADDRESS=bootstrap-notary:10002 + - CORDITE_COMPATIBILITY_ZONE_URL=http://network-map:9080 + - CORDITE_NOTARY=non-validating + - CORDITE_DB_USER=postgres + - CORDITE_DB_PASS=postgres + - CORDITE_DB_DRIVER=org.postgresql.ds.PGSimpleDataSource + - CORDITE_DB_URL=jdbc:postgresql://corda-db:5432/bootstrap + - CORDITE_DB_MAX_POOL_SIZE=5 + depends_on: + - "corda-db" + networks: + cordite: + emea: + image: ${IMAGE_TAG:-cordite/cordite:edge} + restart: always:0 + ports: + - "9082:8080" + volumes: + - emea_certs:/opt/corda/certificates + - emea_artemis:/opt/corda/artemis + - emea_config:/etc/corda + environment: + - CORDITE_LEGAL_NAME=O=Cordite EMEA, OU=Cordite Foundation, L=London,C=GB + - CORDITE_P2P_ADDRESS=emea:10002 + - CORDITE_COMPATIBILITY_ZONE_URL=http://network-map:9080 + - CORDITE_DB_USER=postgres + - CORDITE_DB_PASS=postgres + - CORDITE_DB_DRIVER=org.postgresql.ds.PGSimpleDataSource + - CORDITE_DB_URL=jdbc:postgresql://corda-db:5432/emea + - CORDITE_DB_MAX_POOL_SIZE=5 + - CORDITE_LOG_MODE=json + - CORDA_ARGS=--logging-level=TRACE + depends_on: + - "corda-db" + networks: + cordite: + amer: + image: ${IMAGE_TAG:-cordite/cordite:edge} + restart: always:0 + ports: + - "9083:8080" + volumes: + - amer_certs:/opt/corda/certificates + - amer_artemis:/opt/corda/artemis + - amer_config:/etc/corda + environment: + - CORDITE_LEGAL_NAME=O=Cordite AMER, OU=Cordite Foundation, L=New York City,C=US + - CORDITE_P2P_ADDRESS=amer:10002 + - CORDITE_COMPATIBILITY_ZONE_URL=http://network-map:9080 + - CORDITE_DB_USER=postgres + - CORDITE_DB_PASS=postgres + - CORDITE_DB_DRIVER=org.postgresql.ds.PGSimpleDataSource + - CORDITE_DB_URL=jdbc:postgresql://corda-db:5432/amer + - CORDITE_DB_MAX_POOL_SIZE=5 + - CORDA_ARGS=--logging-level=TRACE + depends_on: + - "corda-db" + networks: + cordite: +volumes: + nms: + postgres_data: + bootstrap_certs: + bootstrap_artemis: + bootstrap_config: + emea_certs: + emea_artemis: + emea_config: + amer_certs: + amer_artemis: + amer_config: diff --git a/test/regression/package-lock.json b/test/regression/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..48e341a0954d5f8c2accf3a6731be28e5bb9c0de --- /dev/null +++ b/test/regression/package-lock.json @@ -0,0 +1,3 @@ +{ + "lockfileVersion": 1 +} diff --git a/test/regression/restart_env.sh b/test/regression/restart_env.sh new file mode 100755 index 0000000000000000000000000000000000000000..02acad6b5d839656d9334f59179e1295cca71037 --- /dev/null +++ b/test/regression/restart_env.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# +# Copyright 2018, Cordite Foundation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# restart environment +# usage ./restart_env.sh + +set -e + +IMAGE_TAG=${1:-cordite/cordite:local} +ENVIRONMENT_SLUG=${2:-min} + +# determine which nodes we need to startup +if [ ${ENVIRONMENT_SLUG} = "min" ] +then + echo "starting a mini cordite network" + declare -a notaries=("bootstrap-notary") + declare -a nodes=("emea amer") + declare -a ports=("9082 9083") +else + echo "starting a full cordite network" + declare -a notaries=("bootstrap-notary") + declare -a nodes=("apac emea amer") + declare -a ports=("9081 9082 9083") +fi + +echo -e "\xE2\x9C\x94 $(date) restarting environment ${ENVIRONMENT_SLUG} with image tag ${IMAGE_TAG}" + + +# clean up any old docker-compose +docker-compose -p ${ENVIRONMENT_SLUG} down + +# start NMS (and wait for it to be ready) +# docker login network-map +docker-compose -p ${ENVIRONMENT_SLUG} up -d network-map +until docker-compose -p ${ENVIRONMENT_SLUG} logs network-map | grep -q "io.cordite.networkmap.NetworkMapApp - started" +do + echo -e "waiting for network-map to start" + sleep 5 +done + +# start databasess +IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} up -d corda-db +until IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} logs corda-db | grep -q "database system is ready to accept connections" +do + echo -e "waiting for corda-db to start up and register..." + sleep 5 +done + +# start notaries (and wait for them to be ready) +# docker login cordite +for NOTARY in $notaries +do + IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} up -d ${NOTARY} +done +for NOTARY in $notaries +do + until IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} logs ${NOTARY} | grep -q "started up and registered" + do + echo -e "waiting for ${NOTARY} to start up and register..." + sleep 5 + done +done + +# we don't need to pause the notaries and formally register them. this should've been done in the previous epoch of the network + +# start regional nodes (and wait for them to be ready) +for NODE in $nodes +do + IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} up -d ${NODE} +done +for NODE in $nodes +do + until IMAGE_TAG=${IMAGE_TAG} docker-compose -p ${ENVIRONMENT_SLUG} logs ${NODE} | grep -q "started up and registered" + do + echo -e "waiting for ${NODE} to start up and register..." + sleep 5 + done +done + +# test endpoints +for PORT in $ports +do + while [[ "$(curl -sSfk -m 5 -o /dev/null -w ''%{http_code}'' https://localhost:${PORT}/api/)" != "200" ]] + do + echo -e "waiting for ${PORT} to return 200..." + sleep 5 + done +done + +echo -e "\xE2\x9C\x94 $(date) environment ${ENVIRONMENT_SLUG} restarted with image tag ${IMAGE_TAG}" \ No newline at end of file diff --git a/test/regression/run.sh b/test/regression/run.sh new file mode 100755 index 0000000000000000000000000000000000000000..2fdfe860c991920c7009d985d4d72850bc8be558 --- /dev/null +++ b/test/regression/run.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# +# Copyright 2018, Cordite Foundation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e # stop on error + +BASELINE_VERSION=${1:-cordite/cordite:v0.4.10} +TEST_VERSION=${2:-cordite/cordite:local} +ENVIRONMENT=${3:-min} + +echo "--------------------------------------" +echo "starting up release version of cordite" +echo "--------------------------------------" +./build_env.sh ${BASELINE_VERSION} ${ENVIRONMENT} + +./cordite -f scripts/step-1-amer.js https://localhost:9083 +./cordite -f scripts/step-2-emea.js https://localhost:9082 + +echo "-----------------------------" +echo "shutting down release version" +echo "-----------------------------" +docker-compose -p ${ENVIRONMENT} down + +echo "----------------------------------------" +echo "starting up the local version of cordite" +echo "----------------------------------------" +./restart_env.sh ${TEST_VERSION} ${ENVIRONMENT} + +./cordite -f scripts/step-3-amer.js https://localhost:9083 +./cordite -f scripts/step-4-emea.js https://localhost:9082 + +docker-compose -p ${ENVIRONMENT} down --volumes +docker volume prune -f \ No newline at end of file diff --git a/test/regression/scripts/common.js b/test/regression/scripts/common.js new file mode 100644 index 0000000000000000000000000000000000000000..bc7a816ba42480b0ed773fe95ac7261dc8e2e9a7 --- /dev/null +++ b/test/regression/scripts/common.js @@ -0,0 +1,243 @@ +/* + * Copyright 2018, Cordite Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// NOTARY + +const notary = notaries.corditeBootstrapNotary.name; +let allNodes; +let nodesByHost; + +// INIT +async function init() { + allNodes = await network.allNodes(); + nodesByHost = allNodes + .flatMap((node) => { + return node.addresses.map((address) => { + return { key: address.host, value: node }; + }); + }) + .reduce((map, item) => { + map[item.key] = item.value; + return map; + }, {}); +} + +// LOGGING + +function logDoing(text) { + console.log(`⭕ ${text}`); +} + +function logDone(text) { + console.log(`✔️ ${text}`); +} + +function logVerified(text) { + console.log(`✅ ${text}`); +} + +function logEmptyLine() { + console.log(); +} + +function logError(text) { + console.log(`❌ ${text}`); +} + +// JSON + +function json(obj, pretty) { + let tabs = 0; + if (pretty) { + tabs = 2; + } + return JSON.stringify(obj, null, tabs); +} + +// NETWORK AND NODES + +function formatNode(node) { + const simpleNode = { + address: `${node.addresses[0].host}:${node.addresses[0].port}`, + name: node.legalIdentities[0].name, + owningKey: node.legalIdentities[0].owningKey, + }; + return json(simpleNode); +} + +function formatNodes(allNodes) { + return allNodes + .map((node) => { + return formatNode(node); + }) + .join("\n"); +} + +async function assertMyHost(host) { + logEmptyLine(); + const nodeInfo = await network.myNodeInfo(); + if (nodeInfo.addresses[0].host !== host) { + throw new Error(`host "${nodeInfo.addresses[0].host}" is not "${host}"`); + } else { + console.log(`connected to ${host}`); + } +} + +async function listAllNodes() { + logEmptyLine(); + logVerified(`nodes on the network:\n${formatNodes(allNodes)}`); +} + +function x500NameForHost(host) { + const node = nodesByHost[host]; + if (!node) { + throw new Error(`host ${host} not found`); + } + return node.legalIdentities[0].name; +} + +function accountAtHost(account, host) { + return `${account}@${x500NameForHost(host)}`; +} + +// ACCOUNTS + +async function ensureAccountExists(account) { + try { + await ledger.getAccount(account); + logDone(`account ${account} exists`); + } catch (err) { + await ledger.createAccount(account, notary); + logDone(`created account ${account}`); + } +} + +async function assertAccountExists(account) { + logDoing(`checking account ${account} exists`); + try { + await ledger.getAccount(account); + logDone(`account ${account} exists`); + } catch (err) { + const msg = `account ${account} does not exist`; + logError(msg); + throw new Error(msg); + } +} + +async function balanceForAccount(account, symbol) { + const zeroBalance = "0.00"; + + const balances = await ledger.balanceForAccount(account); + if (balances.length == 0) { + return zeroBalance; + } + + const filtered = balances.filter((balance) => { + return balance.amountType.symbol == symbol; + }); + + let balance = filtered[0].quantity; + + if (!balance) { + balance = zeroBalance; + } + + return balance; +} + +async function transactionsForAccount(account) { + logDoing(`getting transactions for ${account}`); + const txs = await ledger.transactionsForAccount(account, { + pageNumber: 1, + pageSize: 10000, + }); + logDone(`retrieved transactions for ${account}`); + return txs; +} + +// ASSETS + +async function ensureAssetExists(symbol) { + const tokenTypes = await ledger.listTokenTypes(); + const hasSymbol = tokenTypes.map((tt) => tt.symbol).includes(symbol); + if (hasSymbol) { + logDone(`token type ${symbol} exists`); + } else { + await ledger.createTokenType(symbol, 2, notary); + logDone(`token type ${symbol} created`); + } +} + +async function issueAsset(amount, symbol, account, description) { + logEmptyLine(); + logDoing("preparing issuance..."); + const balanceBefore = await balanceForAccount(account, symbol); + logVerified(`balance for "${account}" is ${balanceBefore}`); + + logDoing(`issuing ${amount} ${symbol} to ${account}`); + await ledger.issueToken(account, amount, symbol, description, notary); + logDone(`issued ${amount} ${symbol} to ${account}`); + + const balanceAfter = await balanceForAccount(account, symbol); + logVerified(`balance for "${account}" is now ${balanceAfter}`); + + const balanceExpected = parseFloat(balanceBefore) + parseFloat(amount); + if (balanceExpected == balanceAfter) { + logVerified("balance is correct"); + } else { + const msg = `new balance is ${balanceAfter} but was expecting ${balanceExpected}`; + logError(msg); + throw new Error(msg); + } +} + +async function transfer( + amount, + symbol, + account, + dstAccount, + dstHost, + description +) { + logEmptyLine(); + logDoing("preparing transfer..."); + const balanceBefore = await balanceForAccount(account, symbol); + logVerified(`balance for "${account}" is ${balanceBefore}`); + + const dst = accountAtHost(dstAccount, dstHost); + logDoing(`about to transfer ${amount} ${symbol} from ${account} to ${dst}`); + const txId = await ledger.transferToken( + amount, + symbol, + account, + dst, + description, + notary + ); + logDone(`done. txid: ${txId}`); + + const balanceAfter = await balanceForAccount(account, symbol); + logVerified(`balance for "${account}" is now ${balanceAfter}`); + + const balanceExpected = parseFloat(balanceBefore) - parseFloat(amount); + if (balanceExpected == balanceAfter) { + logVerified("balance is correct"); + } else { + const msg = `new balance is ${balanceAfter} but was expecting ${balanceExpected}`; + logError(msg); + throw new Error(msg); + } +} diff --git a/test/regression/scripts/step-1-amer.js b/test/regression/scripts/step-1-amer.js new file mode 100644 index 0000000000000000000000000000000000000000..48516acc97bd8f2bb4792b290ac00616b02289c4 --- /dev/null +++ b/test/regression/scripts/step-1-amer.js @@ -0,0 +1,24 @@ +/* + * Copyright 2018, Cordite Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +eval(read("./scripts/common.js")); + +await init(); + +await assertMyHost("amer"); + +await listAllNodes(); + +await ensureAccountExists("ben"); diff --git a/test/regression/scripts/step-2-emea.js b/test/regression/scripts/step-2-emea.js new file mode 100644 index 0000000000000000000000000000000000000000..b2d6878de48cbc5ba1af20efcd2ed85a3f76b79e --- /dev/null +++ b/test/regression/scripts/step-2-emea.js @@ -0,0 +1,30 @@ +/* + * Copyright 2018, Cordite Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +eval(read("./scripts/common.js")); + +await init(); + +await assertMyHost("emea"); + +await listAllNodes(); + +await ensureAccountExists("fuzz"); + +await ensureAssetExists("xtc"); + +await issueAsset("100.00", "xtc", "fuzz", "making an issuances"); + +await transfer("10.00", "xtc", "fuzz", "ben", "amer", "single transfer"); diff --git a/test/regression/scripts/step-3-amer.js b/test/regression/scripts/step-3-amer.js new file mode 100644 index 0000000000000000000000000000000000000000..13cf352f00423bd493098123a0c5553446880cd9 --- /dev/null +++ b/test/regression/scripts/step-3-amer.js @@ -0,0 +1,45 @@ +/* + * Copyright 2018, Cordite Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +eval(read("./scripts/common.js")); + +await init(); + +await assertMyHost("amer"); + +await listAllNodes(); + +const account = "ben"; +const asset = 'xtc'; + +await assertAccountExists(account); + +const balance = await balanceForAccount(account, asset); +if (parseFloat(balance) > 0) { + logDone(`balance for account ${account} is ${balance}`); +} else { + const msg = `balance for ${account} is ${balance}. expected > 0.00`; + logError(msg); + throw new Error(msg); +} + +const txs = await transactionsForAccount(account); +if (txs.length === 0) { + const msg = `expected to find some transactions for account ${account}`; + logError(msg); + throw new Error(msg); +} + +logDone(`found ${txs.length} transactions for account ${account}`); diff --git a/test/regression/scripts/step-4-emea.js b/test/regression/scripts/step-4-emea.js new file mode 100644 index 0000000000000000000000000000000000000000..bb7008a098c71a8fbf4b69405ffd5bc8f7a3b4fe --- /dev/null +++ b/test/regression/scripts/step-4-emea.js @@ -0,0 +1,43 @@ +/* + * Copyright 2018, Cordite Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +eval(read("./scripts/common.js")); + +await init(); + +await assertMyHost("emea"); + +const account = "fuzz"; +const asset = "xtc"; + +await assertAccountExists(account); + +const balance = await balanceForAccount(account, asset); +if (parseFloat(balance) > 0) { + logDone(`balance for account ${account} is ${balance}`); +} else { + const msg = `balance for ${account} is ${balance}. expected > 0.00`; + logError(msg); + throw new Error(msg); +} + +const txs = await transactionsForAccount(account); +if (txs.length === 0) { + const msg = `expected to find some transactions for account ${account}`; + logError(msg); + throw new Error(msg); +} + +logDone(`found ${txs.length} transactions for account ${account}`);