diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 57a44808dd6..06836e7a88f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -48,7 +48,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/nodeos_multiple_version_protocol_feat configure_file(${CMAKE_CURRENT_SOURCE_DIR}/consensus-validation-malicious-producers.py ${CMAKE_CURRENT_BINARY_DIR}/consensus-validation-malicious-producers.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/validate-dirty-db.py ${CMAKE_CURRENT_BINARY_DIR}/validate-dirty-db.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/launcher_test.py ${CMAKE_CURRENT_BINARY_DIR}/launcher_test.py COPYONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/db_modes_test.sh ${CMAKE_CURRENT_BINARY_DIR}/db_modes_test.sh COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/db_modes_test.py ${CMAKE_CURRENT_BINARY_DIR}/db_modes_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/prod_preactivation_test.py ${CMAKE_CURRENT_BINARY_DIR}/prod_preactivation_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version-label.sh ${CMAKE_CURRENT_BINARY_DIR}/version-label.sh COPYONLY) @@ -87,7 +87,8 @@ add_test(NAME validate_dirty_db_test COMMAND tests/validate-dirty-db.py -v --cle set_property(TEST validate_dirty_db_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME launcher_test COMMAND tests/launcher_test.py -v --clean-run --dump-error-detail WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST launcher_test PROPERTY LABELS nonparallelizable_tests) -add_test(NAME db_modes_test COMMAND tests/db_modes_test.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +add_test(NAME db_modes_test COMMAND tests/db_modes_test.py WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST db_modes_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME version-label-test COMMAND tests/version-label.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) # Long running tests diff --git a/tests/db_modes_test.py b/tests/db_modes_test.py new file mode 100755 index 00000000000..2977c7c4c55 --- /dev/null +++ b/tests/db_modes_test.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python3 + +# This test is intended to verify that switching between DB modes "just works". Addtionally +# it tries to make sure the dirty bit behaves as expected even in heap mode. + +from testUtils import Utils + +import decimal +import re +import os +import signal +import time +import subprocess +import shlex +import tempfile +import socket +import sys + +errorExit=Utils.errorExit + +nodeosCmd="./programs/nodeos/nodeos -d {} --config-dir {} \ +--chain-state-db-size-mb 8 --chain-state-db-guard-size-mb 0 --reversible-blocks-db-size-mb 1 \ +--reversible-blocks-db-guard-size-mb 0 -e -peosio --plugin eosio::chain_api_plugin" + +cleosPath="./programs/cleos/cleos" +port=8888 + +def run_and_kill(extraCmd="", killsig=signal.SIGTERM, preCmd=""): + global port + port = 8888 + print("looking for free ports") + tries = 200 + while (tries > 0): + try: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server_address = ('127.0.0.1', port) + sock.bind(server_address) + sock.close() + time.sleep(1) + tries = 0 + except: + tries = tries - 1 + port = port + 1 + # now start nodeos + cmdArr= preCmd + nodeosCmd + " --http-server-address=127.0.0.1:" + str(port) + extraCmd + print("port %d is free now, start to run nodeosCmd with extra parameter \"%s\"" % (port, extraCmd)) + proc=subprocess.Popen(cmdArr, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, preexec_fn=os.setsid) + tries = 10 + ok = False + getInfoCmd = cleosPath + " -u http://127.0.0.1:" + str(port) + "/ get info" + while (tries > 0): + time.sleep(1) + reply = Utils.checkOutput(getInfoCmd, ignoreError=True) + if reply.find("server_version") != -1: + ok = True + time.sleep(1) + break + tries = tries - 1 + if ok is True: + os.killpg(os.getpgid(proc.pid), killsig) + print("got result %d, killed with signal %d" % (ok, killsig)) + return ok + +print("=== db_modes_test.py starts ===") + +tempdir = tempfile.mkdtemp() +nodeosCmd = nodeosCmd.format(tempdir, tempdir) + +print("nodeosCmd is %s" % (nodeosCmd)) + +#new chain with mapped mode +if run_and_kill(" --delete-all-blocks") != True: + errorExit("Failed in new chain with mapped mode") + +#use previous DB with heap mode +if run_and_kill(" --database-map-mode heap") != True: + errorExit("Failed in restart heap mode") + +#test locked mode if max locked memory is unlimited +ulimits = Utils.checkOutput('ulimit -a', ignoreError=True).split("\n") +for row in ulimits: + if row.find("max locked memory") != -1: + print("output of ulimit -a is: %s:" % (row)) + if row.find("unlimited") != -1: + if run_and_kill(" --database-map-mode locked") != True: + errorExit("Failed in restart with locked mode") + else: + print("skip default locked mode test because max locked memory is not unlimited") + break + +#locked mode should fail when it's not possible to lock anything +if run_and_kill(" --database-map-mode locked", preCmd="ulimit -l 0; ") != False: + errorExit("Test Failed in locked mode with ulimit -l 0") + +#But shouldn't result in the dirty flag staying set; so next launch should run +if run_and_kill("") != True: + errorExit("Failed in restart heap mode") + +#Try killing with hard KILL +if run_and_kill("", killsig=signal.SIGKILL) != True: + errorExit("Failed in restart & hardkill in heap mode") + +#should be dirty now +if run_and_kill("") != False: + errorExit("dirty flag test failed") + +#should also still be dirty in heap mode +if run_and_kill(" --database-map-mode heap") != False: + errorExit("dirty flag test failed") + +#start over again! but this time start with heap mode +if run_and_kill(" --delete-all-blocks --database-map-mode heap") != True: + errorExit("Failed in restart heap mode with --delete-all-blocks") + +#Then switch back to mapped +if run_and_kill("") != True: + errorExit("Failed in restart mapped mode") + +#try killing it while in heap mode +if run_and_kill(" --database-map-mode heap", killsig=signal.SIGKILL) != True: + errorExit("Failed in restart heap mode and hardkill") + +#should be dirty if we run in either mode node +if run_and_kill(" --database-map-mode heap") != False: + errorExit("dirty flag test failed in heap mode") + +if run_and_kill("") != False: + errorExit("dirty flag test failed in mapped mode") + +print("=== db_modes_test.py finished successfully ===") + diff --git a/tests/db_modes_test.sh b/tests/db_modes_test.sh deleted file mode 100755 index f29b8ffcb51..00000000000 --- a/tests/db_modes_test.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env bash - -# This test is intended to verify that switching between DB modes "just works". Addtionally -# it tries to make sure the dirty bit behaves as expected even in heap mode. - -set -euo pipefail - -VERBOSE=0 -TEST_LOCKED_MODE=0 - -while getopts ":lv" opt; do - case ${opt} in - l) - TEST_LOCKED_MODE=1 - ;; - v) - VERBOSE=1 - set -o xtrace - ;; - \?) - echo "Use -v for verbose; -l to enable test of locked mode" - exit 1; - ;; - :) - echo "Invalid option" - exit 1; - ;; - esac -done - -EOSIO_STUFF_DIR=$(mktemp -d) -trap "rm -rf $EOSIO_STUFF_DIR" EXIT -NODEOS_LAUNCH_PARAMS="./programs/nodeos/nodeos -d $EOSIO_STUFF_DIR --config-dir $EOSIO_STUFF_DIR \ ---chain-state-db-size-mb 8 --chain-state-db-guard-size-mb 0 --reversible-blocks-db-size-mb 1 \ ---reversible-blocks-db-guard-size-mb 0 -e -peosio" - -run_nodeos() { - if (( $VERBOSE == 0 )); then - $NODEOS_LAUNCH_PARAMS --http-server-address '' --p2p-listen-endpoint '' "$@" 2>/dev/null & - else - $NODEOS_LAUNCH_PARAMS --http-server-address '' --p2p-listen-endpoint '' "$@" & - fi -} - -run_expect_success() { - run_nodeos "$@" - local NODEOS_PID=$! - sleep 5 - kill $NODEOS_PID - wait $NODEOS_PID -} - -run_and_kill() { - run_nodeos "$@" - local NODEOS_PID=$! - sleep 5 - kill -KILL $NODEOS_PID - ! wait $NODEOS_PID -} - -run_expect_failure() { - run_nodeos "$@" - local NODEOS_PID=$! - MYPID=$$ - (sleep 10; kill -ALRM $MYPID) & local TIMER_PID=$! - trap "kill $NODEOS_PID; wait $NODEOS_PID; exit 1" ALRM - sleep 5 - if wait $NODEOS_PID; then exit 1; fi - kill $TIMER_PID - trap ALRM -} - -#new chain with mapped mode -run_expect_success --delete-all-blocks -#use previous DB with heap mode -run_expect_success --database-map-mode heap -#test lock mode if enabled -if (( $TEST_LOCKED_MODE == 1 )); then - run_expect_success --database-map-mode locked -fi -#locked mode should fail when it's not possible to lock anything -ulimit -l 0 -run_expect_failure --database-map-mode locked -#But shouldn't result in the dirty flag staying set; so next launch should run -run_expect_success -#Try killing with KILL -run_and_kill -#should be dirty now -run_expect_failure -#should also still be dirty in heap mode -run_expect_failure --database-map-mode heap - -#start over again! but this time start with heap mode -run_expect_success --delete-all-blocks --database-map-mode heap -#Then switch back to mapped -run_expect_success -#try killing it while in heap mode -run_and_kill --database-map-mode heap -#should be dirty if we run in either mode node -run_expect_failure --database-map-mode heap -run_expect_failure diff --git a/tests/testUtils.py b/tests/testUtils.py index 4235e725ba5..dfd1823dbf7 100755 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -152,8 +152,10 @@ def getChainStrategies(): @staticmethod def checkOutput(cmd, ignoreError=False): - assert(isinstance(cmd, list)) - popen=subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if (isinstance(cmd, list)): + popen=subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + else: + popen=subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) (output,error)=popen.communicate() Utils.CheckOutputDeque.append((output,error,cmd)) if popen.returncode != 0 and not ignoreError: