From 729e93f8a81c96aa52fdaa65fdc204bc133aad76 Mon Sep 17 00:00:00 2001 From: thomasmodeneis Date: Tue, 21 Apr 2020 21:37:10 +0200 Subject: [PATCH] Automated Tests for RPC endpoints #253 (#257) * add RPC integration script that run all tests for ethermint rpc endpoints, updated tester_test.go to rpc_test.go and moved it to package tests --- Makefile | 4 + scripts/integration-test-all.sh | 175 ++++++++++++++++++ .../tester_test.go => tests/rpc_test.go | 58 ++++-- 3 files changed, 222 insertions(+), 15 deletions(-) create mode 100755 scripts/integration-test-all.sh rename rpc/tester/tester_test.go => tests/rpc_test.go (93%) diff --git a/Makefile b/Makefile index 486e62c0..5607e75c 100644 --- a/Makefile +++ b/Makefile @@ -149,6 +149,9 @@ test-import: test-rpc: @${GO_MOD} go test -v --vet=off ./rpc/tester +it-tests: + ./scripts/integration-test-all.sh -q 1 -z 1 -s 10 + godocs: @echo "--> Wait a few seconds and visit http://localhost:6060/pkg/github.com/cosmos/ethermint" godoc -http=:6060 @@ -163,5 +166,6 @@ format: @find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs gofmt -w -s @find . -name '*.go' -type f -not -path "./vendor*" -not -path "*.git*" | xargs misspell -w + .PHONY: build install update-tools tools godocs clean format lint \ test-cli test-race test-unit test test-import diff --git a/scripts/integration-test-all.sh b/scripts/integration-test-all.sh new file mode 100755 index 00000000..1f228a51 --- /dev/null +++ b/scripts/integration-test-all.sh @@ -0,0 +1,175 @@ +#!/bin/bash + +# "stable" mode tests assume data is static +# "live" mode tests assume data dynamic + +SCRIPT=$(basename ${BASH_SOURCE[0]}) +TEST="" +QTD=1 +SLEEP_TIMEOUT=5 +TEST_QTD=1 + +#PORT AND RPC_PORT 3 initial digits, to be concat with a suffix later when node is initialized +RPC_PORT="854" +IP_ADDR="0.0.0.0" +MODE="stable" + +KEY="mykey" +CHAINID=8 +MONIKER="mymoniker" + +## default port prefixes for emintd +NODE_P2P_PORT="2660" +NODE_PORT="2663" +NODE_RPC_PORT="2666" + +usage() { + echo "Usage: $SCRIPT" + echo "Optional command line arguments" + echo "-t -- Test to run. eg: rpc" + echo "-q -- Quantity of nodes to run. eg: 3" + echo "-z -- Quantity of nodes to run tests against eg: 3" + echo "-s -- Sleep between operations in secs. eg: 5" + exit 1 +} + +while getopts "h?t:q:z:s:" args; do +case $args in + h|\?) + usage; + exit;; + t ) TEST=${OPTARG};; + q ) QTD=${OPTARG};; + z ) TEST_QTD=${OPTARG};; + s ) SLEEP_TIMEOUT=${OPTARG};; + esac +done + +set -euxo pipefail + +DATA_DIR=$(mktemp -d -t ethermint-datadir.XXXXX) + +if [[ ! "$DATA_DIR" ]]; then + echo "Could not create $DATA_DIR" + exit 1 +fi + +DATA_CLI_DIR=$(mktemp -d -t ethermint-cli-datadir.XXXXX) + +if [[ ! "$DATA_CLI_DIR" ]]; then + echo "Could not create $DATA_CLI_DIR" + exit 1 +fi + +# Compile ethermint +echo "compiling ethermint" +make build + +# PID array declaration +arr=() + +# PID arraycli declaration +arrcli=() + +init_func() { + echo "create and add new keys" + "$PWD"/build/emintcli config keyring-backend test --home "$DATA_CLI_DIR$i" + "$PWD"/build/emintcli keys add $KEY"$i" --home "$DATA_CLI_DIR$i" --no-backup --chain-id $CHAINID + echo "init Ethermint with moniker=$MONIKER and chain-id=$CHAINID" + "$PWD"/build/emintd init $MONIKER --chain-id $CHAINID --home "$DATA_DIR$i" + echo "init emintcli with chain-id=$CHAINID and config it trust-node true" + "$PWD"/build/emintcli config chain-id $CHAINID --home "$DATA_CLI_DIR$i" + "$PWD"/build/emintcli config output json --home "$DATA_CLI_DIR$i" + "$PWD"/build/emintcli config indent true --home "$DATA_CLI_DIR$i" + "$PWD"/build/emintcli config trust-node true --home "$DATA_CLI_DIR$i" + echo "prepare genesis: Allocate genesis accounts" + "$PWD"/build/emintd add-genesis-account \ + "$(emintcli keys show "$KEY$i" -a --home "$DATA_CLI_DIR$i" )" 1000000000000000000photon,1000000000000000000stake \ + --home "$DATA_DIR$i" --home-client "$DATA_CLI_DIR$i" + echo "prepare genesis: Sign genesis transaction" + "$PWD"/build/emintd gentx --name $KEY"$i" --keyring-backend test --home "$DATA_DIR$i" --home-client "$DATA_CLI_DIR$i" + echo "prepare genesis: Collect genesis tx" + "$PWD"/build/emintd collect-gentxs --home "$DATA_DIR$i" + echo "prepare genesis: Run validate-genesis to ensure everything worked and that the genesis file is setup correctly" + "$PWD"/build/emintd validate-genesis --home "$DATA_DIR$i" +} + +start_func() { + echo "starting ethermint node $i in background ..." + "$PWD"/build/emintd start --pruning=nothing --rpc.unsafe --log_level "main:info,state:info,mempool:info" \ + --p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" --address tcp://$IP_ADDR:$NODE_PORT"$i" --rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ + --home "$DATA_DIR$i" \ + >"$DATA_DIR"/node"$i".log 2>&1 & disown + + ETHERMINT_PID=$! + echo "started ethermint node, pid=$ETHERMINT_PID" + # add PID to array + arr+=("$ETHERMINT_PID") +} + +start_cli_func() { + echo "starting ethermint node $i in background ..." + "$PWD"/build/emintcli rest-server --unlock-key $KEY"$i" --chain-id $CHAINID --trace \ + --laddr "tcp://localhost:$RPC_PORT$i" --node tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \ + --home "$DATA_CLI_DIR$i" --read-timeout 30 --write-timeout 30 \ + >"$DATA_CLI_DIR"/cli"$i".log 2>&1 & disown + + ETHERMINT_CLI_PID=$! + echo "started emintcli node, pid=$ETHERMINT_CLI_PID" + # add PID to array + arrcli+=("$ETHERMINT_CLI_PID") +} + +# Run node with static blockchain database +# For loop N times +for i in $(seq 1 "$QTD"); do + init_func "$i" + start_func "$i" + sleep 1 + start_cli_func "$i" + echo "sleeping $SLEEP_TIMEOUT seconds for startup" + sleep "$SLEEP_TIMEOUT" + echo "done sleeping" +done + +echo "sleeping $SLEEP_TIMEOUT seconds before running tests ... " +sleep "$SLEEP_TIMEOUT" +echo "done sleeping" + +set +e + +if [[ -z $TEST || $TEST == "rpc" ]]; then + + for i in $(seq 1 "$TEST_QTD"); do + HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i" + echo "going to test ethermint node $HOST_RPC ..." + ETHERMINT_INTEGRATION_TEST_MODE=$MODE ETHERMINT_NODE_HOST=$HOST_RPC go test ./tests/... -timeout=300s -v -count=1 + + RPC_FAIL=$? + done + +fi + +stop_func() { + ETHERMINT_PID=$i + echo "shutting down node, pid=$ETHERMINT_PID ..." + + # Shutdown ethermint node + kill -9 "$ETHERMINT_PID" + wait "$ETHERMINT_PID" +} + + +for i in "${arrcli[@]}"; do + stop_func "$i" +done + +for i in "${arr[@]}"; do + stop_func "$i" +done + +if [[ (-z $TEST || $TEST == "rpc") && $RPC_FAIL -ne 0 ]]; then + exit $RPC_FAIL +else + exit 0 +fi diff --git a/rpc/tester/tester_test.go b/tests/rpc_test.go similarity index 93% rename from rpc/tester/tester_test.go rename to tests/rpc_test.go index ebacfdb1..bc2db169 100644 --- a/rpc/tester/tester_test.go +++ b/tests/rpc_test.go @@ -3,9 +3,11 @@ // To run these tests please first ensure you have the emintd running // and have started the RPC service with `emintcli rest-server`. // -// You can configure the desired port (or host) below. +// You can configure the desired ETHERMINT_NODE_HOST and ETHERMINT_INTEGRATION_TEST_MODE +// +// to have it running -package tester +package tests import ( "bytes" @@ -14,6 +16,7 @@ import ( "fmt" "math/big" "net/http" + "os" "testing" "time" @@ -24,14 +27,16 @@ import ( ) const ( - host = "localhost" - port = 8545 addrA = "0xc94770007dda54cF92009BFF0dE90c06F603a09f" addrAStoreKey = 0 ) -var addr = fmt.Sprintf("http://%s:%d", host, port) -var zeroString = "0x0" +var ( + ETHERMINT_INTEGRATION_TEST_MODE = os.Getenv("ETHERMINT_INTEGRATION_TEST_MODE") + ETHERMINT_NODE_HOST = os.Getenv("ETHERMINT_NODE_HOST") + + zeroString = "0x0" +) type Request struct { Version string `json:"jsonrpc"` @@ -52,6 +57,22 @@ type Response struct { Result json.RawMessage `json:"result,omitempty"` } +func TestMain(m *testing.M) { + if ETHERMINT_INTEGRATION_TEST_MODE != "stable" { + _, _ = fmt.Fprintln(os.Stdout, "Going to skip stable test") + return + } + + if ETHERMINT_NODE_HOST == "" { + _, _ = fmt.Fprintln(os.Stdout, "Going to skip stable test, ETHERMINT_NODE_HOST is not defined") + return + } + + // Start all tests + code := m.Run() + os.Exit(code) +} + func createRequest(method string, params interface{}) Request { return Request{ Version: "2.0", @@ -67,29 +88,36 @@ func call(t *testing.T, method string, params interface{}) (*Response, error) { return nil, err } + var rpcRes *Response + time.Sleep(1 * time.Second) /* #nosec */ - res, err := http.Post(addr, "application/json", bytes.NewBuffer(req)) + res, err := http.Post(ETHERMINT_NODE_HOST, "application/json", bytes.NewBuffer(req)) if err != nil { - t.Fatal(err) + t.Log("could not http.Post, ", "err", err) + return nil, err } decoder := json.NewDecoder(res.Body) - var rpcRes *Response + rpcRes = new(Response) err = decoder.Decode(&rpcRes) if err != nil { - t.Fatal(err) - } - - if rpcRes.Error != nil { - return nil, errors.New(rpcRes.Error.Message) + t.Log("could not decoder.Decode, ", "err", err) + return nil, err } err = res.Body.Close() if err != nil { - t.Fatal(err) + t.Log("could not Body.Close, ", "err", err) + return nil, err + } + + if rpcRes.Error != nil { + t.Log("could not rpcRes.Error, ", "err", err) + return nil, errors.New(rpcRes.Error.Message) } return rpcRes, nil + } func TestEth_protocolVersion(t *testing.T) {