[tests] check v0.17.1 and v0.18.1 backwards compatibility

This commit is contained in:
Sjors Provoost
2019-01-05 20:20:42 +01:00
parent ae379cf7d1
commit 8b1460dbd1
10 changed files with 112 additions and 8 deletions

View File

@@ -35,6 +35,7 @@ cache:
- $TRAVIS_BUILD_DIR/depends/built - $TRAVIS_BUILD_DIR/depends/built
- $TRAVIS_BUILD_DIR/depends/sdk-sources - $TRAVIS_BUILD_DIR/depends/sdk-sources
- $TRAVIS_BUILD_DIR/ci/scratch/.ccache - $TRAVIS_BUILD_DIR/ci/scratch/.ccache
- $TRAVIS_BUILD_DIR/releases/$HOST
# macOS # macOS
- $HOME/Library/Caches/Homebrew - $HOME/Library/Caches/Homebrew
- /usr/local/Homebrew - /usr/local/Homebrew
@@ -108,7 +109,7 @@ jobs:
FILE_ENV="./ci/test/00_setup_env_i686_centos.sh" FILE_ENV="./ci/test/00_setup_env_i686_centos.sh"
- stage: test - stage: test
name: 'x86_64 Linux [GOAL: install] [bionic] [uses qt5 dev package and some depends packages] [unsigned char]' name: 'x86_64 Linux [GOAL: install] [bionic] [previous releases, uses qt5 dev package and some depends packages] [unsigned char]'
env: >- env: >-
FILE_ENV="./ci/test/00_setup_env_native_qt5.sh" FILE_ENV="./ci/test/00_setup_env_native_qt5.sh"

View File

@@ -13,7 +13,7 @@ If the repository is not a fresh git clone, you might have to clean files from p
The ci needs to perform various sysadmin tasks such as installing packages or writing to the user's home directory. The ci needs to perform various sysadmin tasks such as installing packages or writing to the user's home directory.
While most of the actions are done inside a docker container, this is not possible for all. Thus, cache directories, While most of the actions are done inside a docker container, this is not possible for all. Thus, cache directories,
such as the depends cache or ccache, are mounted as read-write into the docker container. While it should be fine to run such as the depends cache, previous release binaries, or ccache, are mounted as read-write into the docker container. While it should be fine to run
the ci system locally on you development box, the ci scripts can generally be assumed to have received less review and the ci system locally on you development box, the ci scripts can generally be assumed to have received less review and
testing compared to other parts of the codebase. If you want to keep the work tree clean, you might want to run the ci testing compared to other parts of the codebase. If you want to keep the work tree clean, you might want to run the ci
system in a virtual machine with a Linux operating system of your choice. system in a virtual machine with a Linux operating system of your choice.

View File

@@ -33,6 +33,7 @@ export HOST=${HOST:-$("$BASE_ROOT_DIR/depends/config.guess")}
export USE_BUSY_BOX=${USE_BUSY_BOX:-false} export USE_BUSY_BOX=${USE_BUSY_BOX:-false}
export RUN_UNIT_TESTS=${RUN_UNIT_TESTS:-true} export RUN_UNIT_TESTS=${RUN_UNIT_TESTS:-true}
export RUN_FUNCTIONAL_TESTS=${RUN_FUNCTIONAL_TESTS:-true} export RUN_FUNCTIONAL_TESTS=${RUN_FUNCTIONAL_TESTS:-true}
export TEST_PREVIOUS_RELEASES=${TEST_PREVIOUS_RELEASES:-false}
export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false} export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false}
export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed} export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed}
export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:18.04} export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:18.04}
@@ -50,6 +51,7 @@ export CCACHE_DIR=${CCACHE_DIR:-$BASE_SCRATCH_DIR/.ccache}
export DEPENDS_DIR=${DEPENDS_DIR:-$BASE_ROOT_DIR/depends} export DEPENDS_DIR=${DEPENDS_DIR:-$BASE_ROOT_DIR/depends}
# Folder where the build is done (bin and lib). # Folder where the build is done (bin and lib).
export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out/$HOST} export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out/$HOST}
export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/releases/$HOST}
export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks} export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}
export WINEDEBUG=${WINEDEBUG:-fixme-all} export WINEDEBUG=${WINEDEBUG:-fixme-all}
export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps} export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps}

View File

@@ -11,4 +11,5 @@ export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libhar
export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
export TEST_RUNNER_EXTRA="--coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash export TEST_RUNNER_EXTRA="--coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
export GOAL="install" export GOAL="install"
export TEST_PREVIOUS_RELEASES=true
export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\"" export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-glibc-back-compat --enable-reduce-exports --enable-debug CFLAGS=\"-g0 -O2 -funsigned-char\" CXXFLAGS=\"-g0 -O2 -funsigned-char\""

View File

@@ -40,12 +40,13 @@ fi
mkdir -p "${BASE_SCRATCH_DIR}" mkdir -p "${BASE_SCRATCH_DIR}"
mkdir -p "${CCACHE_DIR}" mkdir -p "${CCACHE_DIR}"
mkdir -p "${PREVIOUS_RELEASES_DIR}"
export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1" export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1"
export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan" export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan"
export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:log_path=${BASE_SCRATCH_DIR}/sanitizer-output/tsan" export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:log_path=${BASE_SCRATCH_DIR}/sanitizer-output/tsan"
export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1" export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS)' | tee /tmp/env env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS|TEST_PREVIOUS_RELEASES|PREVIOUS_RELEASES_DIR)' | tee /tmp/env
if [[ $HOST = *-mingw32 ]]; then if [[ $HOST = *-mingw32 ]]; then
DOCKER_ADMIN="--cap-add SYS_ADMIN" DOCKER_ADMIN="--cap-add SYS_ADMIN"
elif [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764) elif [[ $BITCOIN_CONFIG = *--with-sanitizers=*address* ]]; then # If ran with (ASan + LSan), Docker needs access to ptrace (https://github.com/google/sanitizers/issues/764)
@@ -62,6 +63,7 @@ if [ -z "$RUN_CI_ON_HOST" ]; then
--mount type=bind,src=$BASE_ROOT_DIR,dst=/ro_base,readonly \ --mount type=bind,src=$BASE_ROOT_DIR,dst=/ro_base,readonly \
--mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR \ --mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR \
--mount type=bind,src=$DEPENDS_DIR,dst=$DEPENDS_DIR \ --mount type=bind,src=$DEPENDS_DIR,dst=$DEPENDS_DIR \
--mount type=bind,src=$PREVIOUS_RELEASES_DIR,dst=$PREVIOUS_RELEASES_DIR \
-w $BASE_ROOT_DIR \ -w $BASE_ROOT_DIR \
--env-file /tmp/env \ --env-file /tmp/env \
--name $CONTAINER_NAME \ --name $CONTAINER_NAME \

View File

@@ -35,3 +35,8 @@ if [ -z "$NO_DEPENDS" ]; then
fi fi
DOCKER_EXEC $SHELL_OPTS make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS DOCKER_EXEC $SHELL_OPTS make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS
fi fi
if [ "$TEST_PREVIOUS_RELEASES" = "true" ]; then
BEGIN_FOLD previous-versions
DOCKER_EXEC contrib/devtools/previous_release.sh -b -t "$PREVIOUS_RELEASES_DIR" v0.17.1 v0.18.1
END_FOLD
fi

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Backwards compatibility functional test
Test various backwards compatibility scenarios. Download the previous node binaries:
contrib/devtools/previous_release.sh -b v0.18.1 v0.17.1
Due to RPC changes introduced in various versions the below tests
won't work for older versions without some patches or workarounds.
Use only the latest patch version of each release, unless a test specifically
needs an older patch version.
"""
import os
from test_framework.test_framework import BitcoinTestFramework, SkipTest
from test_framework.util import (
assert_equal,
sync_blocks
)
class BackwardsCompatibilityTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 4
# Add new version after each release:
self.extra_args = [
[], # Pre-release: use to mine blocks
[], # Pre-release: use to receive coins, swap wallets, etc
[], # v0.18.1
[] # v0.17.1
]
def setup_nodes(self):
if os.getenv("TEST_PREVIOUS_RELEASES") == "false":
raise SkipTest("backwards compatibility tests")
releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases"
if not os.path.isdir(releases_path):
if os.getenv("TEST_PREVIOUS_RELEASES") == "true":
raise AssertionError("TEST_PREVIOUS_RELEASES=1 but releases missing: " + releases_path)
raise SkipTest("This test requires binaries for previous releases")
self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
None,
None,
180100,
170100
], binary=[
self.options.bitcoind,
self.options.bitcoind,
releases_path + "/v0.18.1/bin/bitcoind",
releases_path + "/v0.17.1/bin/bitcoind"
], binary_cli=[
self.options.bitcoincli,
self.options.bitcoincli,
releases_path + "/v0.18.1/bin/bitcoin-cli",
releases_path + "/v0.17.1/bin/bitcoin-cli"
])
self.start_nodes()
def run_test(self):
self.nodes[0].generate(101)
sync_blocks(self.nodes)
# Sanity check the test framework:
res = self.nodes[self.num_nodes - 1].getblockchaininfo()
assert_equal(res['blocks'], 101)
if __name__ == '__main__':
BackwardsCompatibilityTest().main()

View File

@@ -369,7 +369,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Public helper methods. These can be accessed by the subclass test scripts. # Public helper methods. These can be accessed by the subclass test scripts.
def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None): def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None, binary_cli=None, versions=None):
"""Instantiate TestNode objects. """Instantiate TestNode objects.
Should only be called once after the nodes have been specified in Should only be called once after the nodes have been specified in
@@ -380,11 +380,17 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
extra_confs = [[]] * num_nodes extra_confs = [[]] * num_nodes
if extra_args is None: if extra_args is None:
extra_args = [[]] * num_nodes extra_args = [[]] * num_nodes
if versions is None:
versions = [None] * num_nodes
if binary is None: if binary is None:
binary = [self.options.bitcoind] * num_nodes binary = [self.options.bitcoind] * num_nodes
if binary_cli is None:
binary_cli = [self.options.bitcoincli] * num_nodes
assert_equal(len(extra_confs), num_nodes) assert_equal(len(extra_confs), num_nodes)
assert_equal(len(extra_args), num_nodes) assert_equal(len(extra_args), num_nodes)
assert_equal(len(versions), num_nodes)
assert_equal(len(binary), num_nodes) assert_equal(len(binary), num_nodes)
assert_equal(len(binary_cli), num_nodes)
for i in range(num_nodes): for i in range(num_nodes):
self.nodes.append(TestNode( self.nodes.append(TestNode(
i, i,
@@ -393,7 +399,8 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
rpchost=rpchost, rpchost=rpchost,
timewait=self.rpc_timeout, timewait=self.rpc_timeout,
bitcoind=binary[i], bitcoind=binary[i],
bitcoin_cli=self.options.bitcoincli, bitcoin_cli=binary_cli[i],
version=versions[i],
coverage_dir=self.options.coveragedir, coverage_dir=self.options.coveragedir,
cwd=self.options.tmpdir, cwd=self.options.tmpdir,
extra_conf=extra_confs[i], extra_conf=extra_confs[i],

View File

@@ -60,7 +60,7 @@ class TestNode():
To make things easier for the test writer, any unrecognised messages will To make things easier for the test writer, any unrecognised messages will
be dispatched to the RPC connection.""" be dispatched to the RPC connection."""
def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False): def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None):
""" """
Kwargs: Kwargs:
start_perf (bool): If True, begin profiling the node with `perf` as soon as start_perf (bool): If True, begin profiling the node with `perf` as soon as
@@ -84,6 +84,7 @@ class TestNode():
# For those callers that need more flexibility, they can just set the args property directly. # For those callers that need more flexibility, they can just set the args property directly.
# Note that common args are set in the config file (see initialize_datadir) # Note that common args are set in the config file (see initialize_datadir)
self.extra_args = extra_args self.extra_args = extra_args
self.version = version
# Configuration for logging is set as command-line args rather than in the bitcoin.conf file. # Configuration for logging is set as command-line args rather than in the bitcoin.conf file.
# This means that starting a bitcoind using the temp dir to debug a failed test won't # This means that starting a bitcoind using the temp dir to debug a failed test won't
# spam debug.log. # spam debug.log.
@@ -91,7 +92,6 @@ class TestNode():
self.binary, self.binary,
"-datadir=" + self.datadir, "-datadir=" + self.datadir,
"-logtimemicros", "-logtimemicros",
"-logthreadnames",
"-debug", "-debug",
"-debugexclude=libevent", "-debugexclude=libevent",
"-debugexclude=leveldb", "-debugexclude=leveldb",
@@ -107,6 +107,9 @@ class TestNode():
"--gen-suppressions=all", "--exit-on-first-error=yes", "--gen-suppressions=all", "--exit-on-first-error=yes",
"--error-exitcode=1", "--quiet"] + self.args "--error-exitcode=1", "--quiet"] + self.args
if self.version is None or self.version >= 190000:
self.args.append("-logthreadnames")
self.cli = TestNodeCLI(bitcoin_cli, self.datadir) self.cli = TestNodeCLI(bitcoin_cli, self.datadir)
self.use_cli = use_cli self.use_cli = use_cli
self.start_perf = start_perf self.start_perf = start_perf
@@ -254,7 +257,11 @@ class TestNode():
return return
self.log.debug("Stopping node") self.log.debug("Stopping node")
try: try:
# Do not use wait argument when testing older nodes, e.g. in feature_backwards_compatibility.py
if self.version is None or self.version >= 180000:
self.stop(wait=wait) self.stop(wait=wait)
else:
self.stop()
except http.client.CannotSendRequest: except http.client.CannotSendRequest:
self.log.exception("Unable to stop node.") self.log.exception("Unable to stop node.")

View File

@@ -158,6 +158,7 @@ BASE_SCRIPTS = [
'feature_assumevalid.py', 'feature_assumevalid.py',
'example_test.py', 'example_test.py',
'wallet_txn_doublespend.py', 'wallet_txn_doublespend.py',
'feature_backwards_compatibility.py',
'wallet_txn_clone.py --mineblock', 'wallet_txn_clone.py --mineblock',
'feature_notifications.py', 'feature_notifications.py',
'rpc_getblockfilter.py', 'rpc_getblockfilter.py',