Skip to content

Commit 8b1460d

Browse files
committed
[tests] check v0.17.1 and v0.18.1 backwards compatibility
1 parent ae379cf commit 8b1460d

File tree

10 files changed

+112
-8
lines changed

10 files changed

+112
-8
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ cache:
3535
- $TRAVIS_BUILD_DIR/depends/built
3636
- $TRAVIS_BUILD_DIR/depends/sdk-sources
3737
- $TRAVIS_BUILD_DIR/ci/scratch/.ccache
38+
- $TRAVIS_BUILD_DIR/releases/$HOST
3839
# macOS
3940
- $HOME/Library/Caches/Homebrew
4041
- /usr/local/Homebrew
@@ -108,7 +109,7 @@ jobs:
108109
FILE_ENV="./ci/test/00_setup_env_i686_centos.sh"
109110
110111
- stage: test
111-
name: 'x86_64 Linux [GOAL: install] [bionic] [uses qt5 dev package and some depends packages] [unsigned char]'
112+
name: 'x86_64 Linux [GOAL: install] [bionic] [previous releases, uses qt5 dev package and some depends packages] [unsigned char]'
112113
env: >-
113114
FILE_ENV="./ci/test/00_setup_env_native_qt5.sh"
114115

ci/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ If the repository is not a fresh git clone, you might have to clean files from p
1313

1414
The ci needs to perform various sysadmin tasks such as installing packages or writing to the user's home directory.
1515
While most of the actions are done inside a docker container, this is not possible for all. Thus, cache directories,
16-
such as the depends cache or ccache, are mounted as read-write into the docker container. While it should be fine to run
16+
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
1717
the ci system locally on you development box, the ci scripts can generally be assumed to have received less review and
1818
testing compared to other parts of the codebase. If you want to keep the work tree clean, you might want to run the ci
1919
system in a virtual machine with a Linux operating system of your choice.

ci/test/00_setup_env.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export HOST=${HOST:-$("$BASE_ROOT_DIR/depends/config.guess")}
3333
export USE_BUSY_BOX=${USE_BUSY_BOX:-false}
3434
export RUN_UNIT_TESTS=${RUN_UNIT_TESTS:-true}
3535
export RUN_FUNCTIONAL_TESTS=${RUN_FUNCTIONAL_TESTS:-true}
36+
export TEST_PREVIOUS_RELEASES=${TEST_PREVIOUS_RELEASES:-false}
3637
export RUN_FUZZ_TESTS=${RUN_FUZZ_TESTS:-false}
3738
export CONTAINER_NAME=${CONTAINER_NAME:-ci_unnamed}
3839
export DOCKER_NAME_TAG=${DOCKER_NAME_TAG:-ubuntu:18.04}
@@ -50,6 +51,7 @@ export CCACHE_DIR=${CCACHE_DIR:-$BASE_SCRATCH_DIR/.ccache}
5051
export DEPENDS_DIR=${DEPENDS_DIR:-$BASE_ROOT_DIR/depends}
5152
# Folder where the build is done (bin and lib).
5253
export BASE_OUTDIR=${BASE_OUTDIR:-$BASE_SCRATCH_DIR/out/$HOST}
54+
export PREVIOUS_RELEASES_DIR=${PREVIOUS_RELEASES_DIR:-$BASE_ROOT_DIR/releases/$HOST}
5355
export SDK_URL=${SDK_URL:-https://bitcoincore.org/depends-sources/sdks}
5456
export WINEDEBUG=${WINEDEBUG:-fixme-all}
5557
export DOCKER_PACKAGES=${DOCKER_PACKAGES:-build-essential libtool autotools-dev automake pkg-config bsdmainutils curl ca-certificates ccache python3 rsync git procps}

ci/test/00_setup_env_native_qt5.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libhar
1111
export DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1"
1212
export TEST_RUNNER_EXTRA="--coverage --extended --exclude feature_dbcrash" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash
1313
export GOAL="install"
14+
export TEST_PREVIOUS_RELEASES=true
1415
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\""

ci/test/04_install.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ fi
4040

4141
mkdir -p "${BASE_SCRATCH_DIR}"
4242
mkdir -p "${CCACHE_DIR}"
43+
mkdir -p "${PREVIOUS_RELEASES_DIR}"
4344

4445
export ASAN_OPTIONS="detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1"
4546
export LSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/lsan"
4647
export TSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/tsan:log_path=${BASE_SCRATCH_DIR}/sanitizer-output/tsan"
4748
export UBSAN_OPTIONS="suppressions=${BASE_ROOT_DIR}/test/sanitizer_suppressions/ubsan:print_stacktrace=1:halt_on_error=1:report_error_type=1"
48-
env | grep -E '^(BITCOIN_CONFIG|BASE_|QEMU_|CCACHE_|WINEDEBUG|LC_ALL|BOOST_TEST_RANDOM|CONFIG_SHELL|(ASAN|LSAN|TSAN|UBSAN)_OPTIONS)' | tee /tmp/env
49+
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
4950
if [[ $HOST = *-mingw32 ]]; then
5051
DOCKER_ADMIN="--cap-add SYS_ADMIN"
5152
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
6263
--mount type=bind,src=$BASE_ROOT_DIR,dst=/ro_base,readonly \
6364
--mount type=bind,src=$CCACHE_DIR,dst=$CCACHE_DIR \
6465
--mount type=bind,src=$DEPENDS_DIR,dst=$DEPENDS_DIR \
66+
--mount type=bind,src=$PREVIOUS_RELEASES_DIR,dst=$PREVIOUS_RELEASES_DIR \
6567
-w $BASE_ROOT_DIR \
6668
--env-file /tmp/env \
6769
--name $CONTAINER_NAME \

ci/test/05_before_script.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,8 @@ if [ -z "$NO_DEPENDS" ]; then
3535
fi
3636
DOCKER_EXEC $SHELL_OPTS make $MAKEJOBS -C depends HOST=$HOST $DEP_OPTS
3737
fi
38+
if [ "$TEST_PREVIOUS_RELEASES" = "true" ]; then
39+
BEGIN_FOLD previous-versions
40+
DOCKER_EXEC contrib/devtools/previous_release.sh -b -t "$PREVIOUS_RELEASES_DIR" v0.17.1 v0.18.1
41+
END_FOLD
42+
fi
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2018-2019 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Backwards compatibility functional test
6+
7+
Test various backwards compatibility scenarios. Download the previous node binaries:
8+
9+
contrib/devtools/previous_release.sh -b v0.18.1 v0.17.1
10+
11+
Due to RPC changes introduced in various versions the below tests
12+
won't work for older versions without some patches or workarounds.
13+
14+
Use only the latest patch version of each release, unless a test specifically
15+
needs an older patch version.
16+
"""
17+
18+
import os
19+
20+
from test_framework.test_framework import BitcoinTestFramework, SkipTest
21+
22+
from test_framework.util import (
23+
assert_equal,
24+
sync_blocks
25+
)
26+
27+
class BackwardsCompatibilityTest(BitcoinTestFramework):
28+
def set_test_params(self):
29+
self.setup_clean_chain = True
30+
self.num_nodes = 4
31+
# Add new version after each release:
32+
self.extra_args = [
33+
[], # Pre-release: use to mine blocks
34+
[], # Pre-release: use to receive coins, swap wallets, etc
35+
[], # v0.18.1
36+
[] # v0.17.1
37+
]
38+
39+
def setup_nodes(self):
40+
if os.getenv("TEST_PREVIOUS_RELEASES") == "false":
41+
raise SkipTest("backwards compatibility tests")
42+
43+
releases_path = os.getenv("PREVIOUS_RELEASES_DIR") or os.getcwd() + "/releases"
44+
if not os.path.isdir(releases_path):
45+
if os.getenv("TEST_PREVIOUS_RELEASES") == "true":
46+
raise AssertionError("TEST_PREVIOUS_RELEASES=1 but releases missing: " + releases_path)
47+
raise SkipTest("This test requires binaries for previous releases")
48+
49+
self.add_nodes(self.num_nodes, extra_args=self.extra_args, versions=[
50+
None,
51+
None,
52+
180100,
53+
170100
54+
], binary=[
55+
self.options.bitcoind,
56+
self.options.bitcoind,
57+
releases_path + "/v0.18.1/bin/bitcoind",
58+
releases_path + "/v0.17.1/bin/bitcoind"
59+
], binary_cli=[
60+
self.options.bitcoincli,
61+
self.options.bitcoincli,
62+
releases_path + "/v0.18.1/bin/bitcoin-cli",
63+
releases_path + "/v0.17.1/bin/bitcoin-cli"
64+
])
65+
66+
self.start_nodes()
67+
68+
def run_test(self):
69+
self.nodes[0].generate(101)
70+
71+
sync_blocks(self.nodes)
72+
73+
# Sanity check the test framework:
74+
res = self.nodes[self.num_nodes - 1].getblockchaininfo()
75+
assert_equal(res['blocks'], 101)
76+
77+
if __name__ == '__main__':
78+
BackwardsCompatibilityTest().main()

test/functional/test_framework/test_framework.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def run_test(self):
369369

370370
# Public helper methods. These can be accessed by the subclass test scripts.
371371

372-
def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None):
372+
def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None, binary_cli=None, versions=None):
373373
"""Instantiate TestNode objects.
374374
375375
Should only be called once after the nodes have been specified in
@@ -380,11 +380,17 @@ def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None):
380380
extra_confs = [[]] * num_nodes
381381
if extra_args is None:
382382
extra_args = [[]] * num_nodes
383+
if versions is None:
384+
versions = [None] * num_nodes
383385
if binary is None:
384386
binary = [self.options.bitcoind] * num_nodes
387+
if binary_cli is None:
388+
binary_cli = [self.options.bitcoincli] * num_nodes
385389
assert_equal(len(extra_confs), num_nodes)
386390
assert_equal(len(extra_args), num_nodes)
391+
assert_equal(len(versions), num_nodes)
387392
assert_equal(len(binary), num_nodes)
393+
assert_equal(len(binary_cli), num_nodes)
388394
for i in range(num_nodes):
389395
self.nodes.append(TestNode(
390396
i,
@@ -393,7 +399,8 @@ def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None):
393399
rpchost=rpchost,
394400
timewait=self.rpc_timeout,
395401
bitcoind=binary[i],
396-
bitcoin_cli=self.options.bitcoincli,
402+
bitcoin_cli=binary_cli[i],
403+
version=versions[i],
397404
coverage_dir=self.options.coveragedir,
398405
cwd=self.options.tmpdir,
399406
extra_conf=extra_confs[i],

test/functional/test_framework/test_node.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class TestNode():
6060
To make things easier for the test writer, any unrecognised messages will
6161
be dispatched to the RPC connection."""
6262

63-
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):
63+
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):
6464
"""
6565
Kwargs:
6666
start_perf (bool): If True, begin profiling the node with `perf` as soon as
@@ -84,14 +84,14 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cl
8484
# For those callers that need more flexibility, they can just set the args property directly.
8585
# Note that common args are set in the config file (see initialize_datadir)
8686
self.extra_args = extra_args
87+
self.version = version
8788
# Configuration for logging is set as command-line args rather than in the bitcoin.conf file.
8889
# This means that starting a bitcoind using the temp dir to debug a failed test won't
8990
# spam debug.log.
9091
self.args = [
9192
self.binary,
9293
"-datadir=" + self.datadir,
9394
"-logtimemicros",
94-
"-logthreadnames",
9595
"-debug",
9696
"-debugexclude=libevent",
9797
"-debugexclude=leveldb",
@@ -107,6 +107,9 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, bitcoind, bitcoin_cl
107107
"--gen-suppressions=all", "--exit-on-first-error=yes",
108108
"--error-exitcode=1", "--quiet"] + self.args
109109

110+
if self.version is None or self.version >= 190000:
111+
self.args.append("-logthreadnames")
112+
110113
self.cli = TestNodeCLI(bitcoin_cli, self.datadir)
111114
self.use_cli = use_cli
112115
self.start_perf = start_perf
@@ -254,7 +257,11 @@ def stop_node(self, expected_stderr='', wait=0):
254257
return
255258
self.log.debug("Stopping node")
256259
try:
257-
self.stop(wait=wait)
260+
# Do not use wait argument when testing older nodes, e.g. in feature_backwards_compatibility.py
261+
if self.version is None or self.version >= 180000:
262+
self.stop(wait=wait)
263+
else:
264+
self.stop()
258265
except http.client.CannotSendRequest:
259266
self.log.exception("Unable to stop node.")
260267

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
'feature_assumevalid.py',
159159
'example_test.py',
160160
'wallet_txn_doublespend.py',
161+
'feature_backwards_compatibility.py',
161162
'wallet_txn_clone.py --mineblock',
162163
'feature_notifications.py',
163164
'rpc_getblockfilter.py',

0 commit comments

Comments
 (0)