From 9f076ed70c5680e056cffad794e3b46feeaa786e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Sun, 6 Nov 2022 22:22:21 +0100 Subject: [PATCH] ci: refactor uitests to use multiple stages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Please do not run 20 different things in a single stage. It makes debugging much harder than it needs to be, since now you can see at a glance the startup of which container fails easily. Changes: - Starting of Ganache and Nim-Waku containers extracted to separate stages - Cleanup of containers moved to `cleanup` step after tests are executed - Many variables moved to `enrivonment` section for job and some stages - The `throttle` effect narrowed down just to the `Tests` stage and not whole job - RPC API is used to get the Multiaddress of Nim-Waku node instead of hardcoding key - Removed no longer necessary `status-go` history node related files - `Jenkinsfile.uitests` was renamed to `Jenkinsfile.e2e` to match CI job names Signed-off-by: Jakub SokoĊ‚owski --- ci/Jenkinsfile.e2e | 181 +++++++++++++++++++++++++++++++++++++ ci/Jenkinsfile.uitests | 149 ------------------------------ ci/mailserver/config.json | 29 ------ ci/mailserver/get_enode.sh | 31 ------- scripts/rpc.sh | 39 ++++++++ 5 files changed, 220 insertions(+), 209 deletions(-) create mode 100644 ci/Jenkinsfile.e2e delete mode 100644 ci/Jenkinsfile.uitests delete mode 100644 ci/mailserver/config.json delete mode 100755 ci/mailserver/get_enode.sh create mode 100755 scripts/rpc.sh diff --git a/ci/Jenkinsfile.e2e b/ci/Jenkinsfile.e2e new file mode 100644 index 0000000000..f009c3eddd --- /dev/null +++ b/ci/Jenkinsfile.e2e @@ -0,0 +1,181 @@ +library 'status-jenkins-lib@v1.6.1' + +/* Options section can't access functions in objects. */ +def isPRBuild = utils.isPRBuild() + +pipeline { + agent { label 'linux' } + + parameters { + booleanParam( + name: 'RELEASE', + description: 'Decides whether binaries are built with debug symbols.', + defaultValue: params.RELEASE ?: false + ) + choice( + name: 'VERBOSE', + description: 'Level of verbosity based on nimbus-build-system setup.', + choices: ['0', '1', '2'] + ) + } + + options { + timestamps() + /* Prevent Jenkins jobs from running forever */ + timeout(time: 120, unit: 'MINUTES') + /* manage how many builds we keep */ + buildDiscarder(logRotator( + numToKeepStr: '10', + daysToKeepStr: '30', + artifactNumToKeepStr: '3', + )) + /* Throttle number of concurrent builds. */ + throttleJobProperty( + throttleEnabled: true, + throttleOption: 'category', + maxConcurrentPerNode: 1, + maxConcurrentTotal: 1 + ) + /* Abort old PR builds. */ + disableConcurrentBuilds( + abortPrevious: isPRBuild + ) + } + + environment { + TARGET = 'e2e' + /* Improve make performance */ + MAKEFLAGS = "-j4 V=${params.VERBOSE}" + /* Disable colors in Nim compiler logs */ + NIMFLAGS = '--colors:off' + /* Makefile assumes the compiler folder is included */ + QTDIR = '/opt/qt/5.14.2/gcc_64' + /* Include library in order to compile the project */ + LD_LIBRARY_PATH = "$QTDIR/lib:$WORKSPACE/vendor/status-go/build/bin:$WORKSPACE/vendor/status-keycard-go/build/libkeycard/" + /* Container ports */ + RPC_PORT = "${8545 + env.EXECUTOR_NUMBER.toInteger()}" + P2P_PORT = "${6010 + env.EXECUTOR_NUMBER.toInteger()}" + /* Ganache config */ + GANACHE_RPC_PORT = "${9545 + env.EXECUTOR_NUMBER.toInteger()}" + GANACHE_MNEMONIC = 'pelican chief sudden oval media rare swamp elephant lawsuit wheat knife initial' + } + + stages { + stage('Deps') { + steps { + sh 'make update' + sh 'make deps' + } + } + + stage('status-go') { + steps { + sh 'make status-go' + } + } + + stage('build') { + environment { + GANACHE_NETWORK_RPC_URL = "http://localhost:${env.GANACHE_RPC_PORT}" + } + steps { + sh 'make' + } + } + + stage('Containers') { + parallel { + stage('Ganache') { steps { script { + ganache = docker.image( + 'trufflesuite/ganache:v7.4.1' + ).run( + ["-p 127.0.0.1:${env.GANACHE_RPC_PORT}:8545", + "-v ${env.WORKSPACE}/test/ui-test/fixtures/ganache-dbs/goerli:/goerli-db"].join(' '), + ["-m='${GANACHE_MNEMONIC}'", "-e=10", + '--chain.chainId=5', + '--database.dbPath=/goerli-db'].join(' ') + ) + } } } + + stage('Nim-Waku') { steps { script { + nimwaku = docker.image( + 'statusteam/nim-waku:v0.13.0' + ).run( + ["-p 127.0.0.1:${env.RPC_PORT}:8545", + "-p 127.0.0.1:${env.P2P_PORT}:30303/tcp", + "-p 127.0.0.1:${env.P2P_PORT}:30303/udp", + "-v ${env.WORKSPACE}/ci/mailserver/config.json:/config.json"].join(' '), + ['--store=true', + '--keep-alive=true', + '--rpc-address=0.0.0.0', + '--nat=none'].join(' ') + ) + env.TEST_PEER_ENR = getPeerAddress() + } } } + } + } + + stage('Tests') { + options { + throttle(categories: ['status-desktop-e2e-tests']) + } + steps { script { + wrap([ + $class: 'Xvfb', + autoDisplayName: true, + parallelBuild: true, + screen: '2560x1440x24', + ]) { script { + def result = squish([ + extraOptions: [ + '--retry', '2', + '--tags', '~mayfail', + '--tags', '~merge', + '--tags', '~relyon-mailserver', + '--config', 'addAUT', 'nim_status_client', + "${WORKSPACE}/bin", + ].join('\n'), + squishPackageName: 'squish-6.7.2-qt514x-linux64', + testSuite: "${WORKSPACE}/test/ui-test/testSuites/*", + ]) + print("Squish run result: ${result}") + if (!['SUCCESS', 'UNSTABLE'].contains(result)) { + throw new Exception('Squish run failed!') + } + } } + } } + post { + failure { script { + sh("docker logs ${nimwaku.id}") + sh("docker logs ${ganache.id}") + } } + } + } + } + + post { + success { script { + github.notifyPR(true) + } } + failure { script { + github.notifyPR(false) + } } + always { script { /* No artifact but a PKG_URL is necessary. */ + env.PKG_URL = "${currentBuild.absoluteUrl}/consoleText" + } } + cleanup { script { + sh './scripts/clean-git.sh' + if (binding.hasVariable('ganache')) { ganache.stop() } + if (binding.hasVariable('nimwaku')) { nimwaku.stop() } + } } + } +} + +def getPeerAddress() { + def rpcResp = sh( + script: "${env.WORKSPACE}/scripts/rpc.sh get_waku_v2_debug_v1_info", + returnStdout: true + ).trim() + assert rpcResp : 'Could not get node address from RPC API!' + return readJSON(text: rpcResp)['result']['listenAddresses'][0] +} diff --git a/ci/Jenkinsfile.uitests b/ci/Jenkinsfile.uitests deleted file mode 100644 index 46b1f82977..0000000000 --- a/ci/Jenkinsfile.uitests +++ /dev/null @@ -1,149 +0,0 @@ -library 'status-jenkins-lib@v1.6.2' - -/* Options section can't access functions in objects. */ -def isPRBuild = utils.isPRBuild() - -pipeline { - agent { label 'linux' } - - parameters { - booleanParam( - name: 'RELEASE', - description: 'Decides whether binaries are built with debug symbols.', - defaultValue: params.RELEASE ?: false - ) - choice( - name: 'VERBOSE', - description: 'Level of verbosity based on nimbus-build-system setup.', - choices: ['0', '1', '2'] - ) - } - - options { - timestamps() - /* Prevent Jenkins jobs from running forever */ - timeout(time: 120, unit: 'MINUTES') - /* manage how many builds we keep */ - buildDiscarder(logRotator( - numToKeepStr: '10', - daysToKeepStr: '30', - artifactNumToKeepStr: '3', - )) - /* Throttle number of concurrent builds. */ - throttleJobProperty( - throttleEnabled: true, - throttleOption: 'category', - categories: ['status-desktop-e2e-tests'], - maxConcurrentPerNode: 1, - maxConcurrentTotal: 1 - ) - /* Abort old PR builds. */ - disableConcurrentBuilds( - abortPrevious: isPRBuild - ) - } - - environment { - TARGET = 'e2e' - /* Improve make performance */ - MAKEFLAGS = "-j4 V=${params.VERBOSE}" - /* Disable colors in Nim compiler logs */ - NIMFLAGS = '--colors:off' - /* Makefile assumes the compiler folder is included */ - QTDIR = "/opt/qt/5.14.2/gcc_64" - /* Control output the filename */ - STATUS_CLIENT_APPIMAGE = "pkg/${utils.pkgFilename(ext: 'AppImage')}" - STATUS_CLIENT_TARBALL = "pkg/${utils.pkgFilename(ext: 'tar.gz')}" - /* Include library in order to compile the project */ - LD_LIBRARY_PATH = "$QTDIR/lib:$WORKSPACE/vendor/status-go/build/bin:$WORKSPACE/vendor/status-keycard-go/build/libkeycard/" - INFURA_TOKEN = "cd313fedd0dd4699b194d72b5184be06" - GANACHE_NETWORK_RPC_URL = "http://0.0.0.0:${855 + env.EXECUTOR_NUMBER}" - } - - stages { - stage('Deps') { - steps { - /* trigger fetching of git submodules */ - sh 'make check-pkg-target-linux' - /* TODO: Re-add caching of Nim compiler. */ - sh 'make deps' - } - } - - stage('status-go') { - steps { sh 'make status-go' } - } - - stage('build') { - steps { sh 'make' } - - } - - stage('Tests') { - steps { - script { - def goerli_rpc_port = 855 + env.EXECUTOR_NUMBER - def mnemonic = "pelican chief sudden oval media rare swamp elephant lawsuit wheat knife initial" - def goerli_db_path = "$WORKSPACE/test/ui-test/fixtures/ganache-dbs/goerli" - def tcp_port = 6010 + env.EXECUTOR_NUMBER - docker.image('trufflesuite/ganache:v7.4.1').withRun( - "-p 127.0.0.1:${goerli_rpc_port}:8545 -v ${goerli_db_path}:/goerli-db", - "-e 10 -m='${mnemonic}' --chain.chainId 5 --database.dbPath /goerli-db" - ) { c -> - docker.image('statusteam/nim-waku').withRun( - "-p 127.0.0.1:${tcp_port}:60000/tcp", - "--use-db=true --persist-messages=true --nat=none --nodekey=1122334455667788990011223344556677889900112233445566778899001122" - ) { c2 -> - env.PEER_ENR = "/ip4/127.0.0.1/tcp/" + tcp_port + "/p2p/16Uiu2HAmMGhfSTUzKbsjMWxc6T1X4wiTWSF1bEWSLjAukCm7KiHV" - withEnv(["TEST_PEER_ENR=${env.PEER_ENR}"]){ - wrap([ - $class: 'Xvfb', - autoDisplayName: true, - parallelBuild: true, - screen: '2560x1440x24', - ]) { - script { - def res = squish([ - extraOptions: ''' - --retry - 2 - - --tags - ~mayfail - - --tags - ~merge - - --tags - ~relyon-mailserver - - --config - addAUT - nim_status_client - ${WORKSPACE}/bin - ''', - squishPackageName: 'squish-6.7.2-qt514x-linux64', - testSuite: '${WORKSPACE}/test/ui-test/testSuites/*', - ]) - echo res - if ( res == "SUCCESS" || res == "UNSTABLE" ) { - return - } - throw new Exception("squish test didn't end with success") - } - } - } - } - sh "docker logs ${c.id}" - } - } - } - } - } - - post { - success { script { github.notifyPR(true) } } - failure { script { github.notifyPR(false) } } - cleanup { sh './scripts/clean-git.sh' } - } -} diff --git a/ci/mailserver/config.json b/ci/mailserver/config.json deleted file mode 100644 index 6ff99219ad..0000000000 --- a/ci/mailserver/config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "Rendezvous": false, - "NoDiscovery": true, - "ClusterConfig": { - "Enabled": true, - "Fleet": "eth.prod", - "BootNodes": [], - "TrustedMailServers": [], - "PushNotificationsServers": [], - "StaticNodes": [] - }, - "ListenAddr": "0.0.0.0:30303", - "HTTPEnabled": true, - "HTTPHost": "0.0.0.0", - "HTTPPort": 8545, - "MaxPeers": 50, - "DataDir": "/var/tmp/status-go-mailserver", - "APIModules": "eth,web3,admin,waku,wakuext", - "RegisterTopics": [ - "whispermail" - ], - "WakuConfig": { - "Enabled": true, - "EnableMailServer": true, - "DataDir": "/var/tmp/status-go-mailserver/waku", - "MailServerPassword": "status-offline-inbox", - "MailServerDataRetention": 30 - } -} diff --git a/ci/mailserver/get_enode.sh b/ci/mailserver/get_enode.sh deleted file mode 100755 index 917607ad60..0000000000 --- a/ci/mailserver/get_enode.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env bash - -RPC_ADDR="${RPC_ADDR:-localhost}" -RPC_PORT="${RPC_PORT:-8545}" -MAILSERVER_PORT="${MAILSERVER_PORT:-30303}" -# might be provided by parent -if [[ -z "${PUBLIC_IP}" ]]; then - PUBLIC_IP=$(curl -s https://ipecho.net/plain) -fi - -# query local -RESP_JSON=$( - curl -sS --retry 3 --retry-connrefused \ - -X POST http://${RPC_ADDR}:${RPC_PORT}/ \ - -H 'Content-type: application/json' \ - -d '{"jsonrpc":"2.0","method":"admin_nodeInfo","params":[],"id":1}' -) -if [[ "$?" -ne 0 ]]; then - echo "RPC port not up, unable to query enode address!" 1>&2 - exit 1 -fi - -# extract enode from JSON response -ENODE_RAW=$(echo "${RESP_JSON}" | jq -r '.result.enode') -# drop arguments at the end of enode address -ENODE_CLEAN=$(echo "${ENODE_RAW}" | grep -oP '\Kenode://[^?]+') - -ENODE=$(echo "${ENODE_CLEAN}" | sed \ - -e "s/:30303/:${MAILSERVER_PORT}/") - -echo "${ENODE}" diff --git a/scripts/rpc.sh b/scripts/rpc.sh new file mode 100755 index 0000000000..0069ff17e8 --- /dev/null +++ b/scripts/rpc.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +# vim: set ft=sh: + +RPC_PORT="${RPC_PORT:-8545}" +RPC_HOST="${RPC_HOST:-127.0.0.1}" + +METHOD="$1" +shift +PARAMS=("$@") + +if [[ -z "${METHOD}" ]]; then + echo "No method specified!" >&2 + exit 1 +fi +if [[ -n "${PARAMS}" ]]; then + PARAMS_STR=$(printf '%s\",\"' "${PARAMS[@]}") + # Params are a nested array because of a bug in nim-json-rpc. + # https://github.com/status-im/nim-json-rpc/issues/90 + PARAMS_STR="[\"${PARAMS_STR%%\",\"}\"]" +else + PARAMS_STR='' +fi + +PAYLOAD="{ + \"id\": 1, + \"jsonrpc\": \"2.0\", + \"method\": \"${METHOD}\", + \"params\": [${PARAMS_STR}] +}" + +# The jq script checks if error exists and adjusts exit code. +curl --request POST \ + --silent \ + --show-error \ + --fail-with-body \ + --header 'Content-type:application/json' \ + --data "${PAYLOAD}" \ + "${RPC_HOST}:${RPC_PORT}" | \ + jq -e '., if .error != null then null|halt_error(2) else halt end'