Skip to content

Commit d5ea8f4

Browse files
author
MarcoFalke
committed
Merge #16509: test: Adapt test framework for chains other than "regtest"
faf3683 test: Avoid hardcoding the chain name in combine_logs (MarcoFalke) fa8a1d7 test: Adapt test framework for chains other than "regtest" (MarcoFalke) 68f5466 test: Fix “local variable 'e' is assigned to but never used” (Ben Woosley) Pull request description: This is required for various work in progress: * testchains #8994 * signet #16411 * some of my locally written tests While it will be unused in the master branch as of now, it will make all of those pull requests shorter. Thus review for non-regtest tests can focus on the actual changes and not some test framework changes. ACKs for top commit: jonatack: ACK faf3683, ran tests and reviewed the code. Tree-SHA512: 35add66c12cab68f2fac8f7c7d47c604d3f24eae9336ff78f83e2c92b3dc08a25e7f4217199bac5393dd3fb72f945bba9c001d6fbb8efd298c88858075fcb3d6
2 parents c77f7cd + faf3683 commit d5ea8f4

File tree

8 files changed

+59
-45
lines changed

8 files changed

+59
-45
lines changed

test/functional/combine_logs.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import argparse
1010
from collections import defaultdict, namedtuple
11+
import glob
1112
import heapq
1213
import itertools
1314
import os
@@ -76,9 +77,17 @@ def read_logs(tmp_dir):
7677
Delegates to generator function get_log_events() to provide individual log events
7778
for each of the input log files."""
7879

80+
# Find out what the folder is called that holds the debug.log file
81+
chain = glob.glob("{}/node0/*/debug.log".format(tmp_dir))
82+
if chain:
83+
chain = chain[0] # pick the first one if more than one chain was found (should never happen)
84+
chain = re.search('node0/(.+?)/debug\.log$', chain).group(1) # extract the chain name
85+
else:
86+
chain = 'regtest' # fallback to regtest (should only happen when none exists)
87+
7988
files = [("test", "%s/test_framework.log" % tmp_dir)]
8089
for i in itertools.count():
81-
logfile = "{}/node{}/regtest/debug.log".format(tmp_dir, i)
90+
logfile = "{}/node{}/{}/debug.log".format(tmp_dir, i, chain)
8291
if not os.path.isfile(logfile):
8392
break
8493
files.append(("node%d" % i, logfile))
@@ -164,25 +173,26 @@ def get_log_events(source, logfile):
164173

165174

166175
def print_logs_plain(log_events, colors):
167-
"""Renders the iterator of log events into text."""
168-
for event in log_events:
169-
lines = event.event.splitlines()
170-
print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, lines[0], colors["reset"]))
171-
if len(lines) > 1:
172-
for line in lines[1:]:
173-
print("{0}{1}{2}".format(colors[event.source.rstrip()], line, colors["reset"]))
176+
"""Renders the iterator of log events into text."""
177+
for event in log_events:
178+
lines = event.event.splitlines()
179+
print("{0} {1: <5} {2} {3}".format(colors[event.source.rstrip()], event.source, lines[0], colors["reset"]))
180+
if len(lines) > 1:
181+
for line in lines[1:]:
182+
print("{0}{1}{2}".format(colors[event.source.rstrip()], line, colors["reset"]))
174183

175184

176185
def print_logs_html(log_events):
177-
"""Renders the iterator of log events into html."""
178-
try:
179-
import jinja2
180-
except ImportError:
181-
print("jinja2 not found. Try `pip install jinja2`")
182-
sys.exit(1)
183-
print(jinja2.Environment(loader=jinja2.FileSystemLoader('./'))
186+
"""Renders the iterator of log events into html."""
187+
try:
188+
import jinja2
189+
except ImportError:
190+
print("jinja2 not found. Try `pip install jinja2`")
191+
sys.exit(1)
192+
print(jinja2.Environment(loader=jinja2.FileSystemLoader('./'))
184193
.get_template('combined_log_template.html')
185194
.render(title="Combined Logs from testcase", log_events=[event._asdict() for event in log_events]))
186195

196+
187197
if __name__ == '__main__':
188198
main()

test/functional/feature_assumevalid.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def send_blocks_until_disconnected(self, p2p_conn):
7272
break
7373
try:
7474
p2p_conn.send_message(msg_block(self.blocks[i]))
75-
except IOError as e:
75+
except IOError:
7676
assert not p2p_conn.is_connected
7777
break
7878

test/functional/feature_blocksdir.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ def set_test_params(self):
1818

1919
def run_test(self):
2020
self.stop_node(0)
21-
assert os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest", "blocks"))
21+
assert os.path.isdir(os.path.join(self.nodes[0].datadir, self.chain, "blocks"))
2222
assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "blocks"))
2323
shutil.rmtree(self.nodes[0].datadir)
24-
initialize_datadir(self.options.tmpdir, 0)
24+
initialize_datadir(self.options.tmpdir, 0, self.chain)
2525
self.log.info("Starting with nonexistent blocksdir ...")
2626
blocksdir_path = os.path.join(self.options.tmpdir, 'blocksdir')
2727
self.nodes[0].assert_start_raises_init_error(["-blocksdir=" + blocksdir_path], 'Error: Specified blocks directory "{}" does not exist.'.format(blocksdir_path))
@@ -30,8 +30,8 @@ def run_test(self):
3030
self.start_node(0, ["-blocksdir=" + blocksdir_path])
3131
self.log.info("mining blocks..")
3232
self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address)
33-
assert os.path.isfile(os.path.join(blocksdir_path, "regtest", "blocks", "blk00000.dat"))
34-
assert os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest", "blocks", "index"))
33+
assert os.path.isfile(os.path.join(blocksdir_path, self.chain, "blocks", "blk00000.dat"))
34+
assert os.path.isdir(os.path.join(self.nodes[0].datadir, self.chain, "blocks", "index"))
3535

3636

3737
if __name__ == '__main__':

test/functional/interface_bitcoin_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def run_test(self):
2929
rpc_response = self.nodes[0].getblockchaininfo()
3030
assert_equal(cli_response, rpc_response)
3131

32-
user, password = get_auth_cookie(self.nodes[0].datadir)
32+
user, password = get_auth_cookie(self.nodes[0].datadir, self.chain)
3333

3434
self.log.info("Test -stdinrpcpass option")
3535
assert_equal(0, self.nodes[0].cli('-rpcuser=%s' % user, '-stdinrpcpass', input=password).getblockcount())

test/functional/rpc_bind.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def run_allowip_test(self, allow_ips, rpchost, rpcport):
5555
self.nodes[0].rpchost = None
5656
self.start_nodes([node_args])
5757
# connect to node through non-loopback interface
58-
node = get_rpc_proxy(rpc_url(self.nodes[0].datadir, 0, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir)
58+
node = get_rpc_proxy(rpc_url(self.nodes[0].datadir, 0, self.chain, "%s:%d" % (rpchost, rpcport)), 0, coveragedir=self.options.coveragedir)
5959
node.getnetworkinfo()
6060
self.stop_nodes()
6161

test/functional/test_framework/test_framework.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
9191

9292
def __init__(self):
9393
"""Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method"""
94+
self.chain = 'regtest'
9495
self.setup_clean_chain = False
9596
self.nodes = []
9697
self.network_thread = None
@@ -192,18 +193,18 @@ def main(self):
192193
self.setup_network()
193194
self.run_test()
194195
success = TestStatus.PASSED
195-
except JSONRPCException as e:
196+
except JSONRPCException:
196197
self.log.exception("JSONRPC error")
197198
except SkipTest as e:
198199
self.log.warning("Test Skipped: %s" % e.message)
199200
success = TestStatus.SKIPPED
200-
except AssertionError as e:
201+
except AssertionError:
201202
self.log.exception("Assertion failed")
202-
except KeyError as e:
203+
except KeyError:
203204
self.log.exception("Key error")
204-
except Exception as e:
205+
except Exception:
205206
self.log.exception("Unexpected exception caught during testing")
206-
except KeyboardInterrupt as e:
207+
except KeyboardInterrupt:
207208
self.log.warning("Exiting after keyboard interrupt")
208209

209210
if success == TestStatus.FAILED and self.options.pdbonfailure:
@@ -342,6 +343,7 @@ def add_nodes(self, num_nodes, extra_args=None, *, rpchost=None, binary=None):
342343
self.nodes.append(TestNode(
343344
i,
344345
get_datadir_path(self.options.tmpdir, i),
346+
chain=self.chain,
345347
rpchost=rpchost,
346348
timewait=self.rpc_timeout,
347349
bitcoind=binary[i],
@@ -477,11 +479,12 @@ def _initialize_chain(self):
477479
if not os.path.isdir(cache_node_dir):
478480
self.log.debug("Creating cache directory {}".format(cache_node_dir))
479481

480-
initialize_datadir(self.options.cachedir, CACHE_NODE_ID)
482+
initialize_datadir(self.options.cachedir, CACHE_NODE_ID, self.chain)
481483
self.nodes.append(
482484
TestNode(
483485
CACHE_NODE_ID,
484486
cache_node_dir,
487+
chain=self.chain,
485488
extra_conf=["bind=127.0.0.1"],
486489
extra_args=['-disablewallet'],
487490
rpchost=None,
@@ -515,7 +518,7 @@ def _initialize_chain(self):
515518
self.nodes = []
516519

517520
def cache_path(*paths):
518-
return os.path.join(cache_node_dir, "regtest", *paths)
521+
return os.path.join(cache_node_dir, self.chain, *paths)
519522

520523
os.rmdir(cache_path('wallets')) # Remove empty wallets dir
521524
for entry in os.listdir(cache_path()):
@@ -526,15 +529,15 @@ def cache_path(*paths):
526529
self.log.debug("Copy cache directory {} to node {}".format(cache_node_dir, i))
527530
to_dir = get_datadir_path(self.options.tmpdir, i)
528531
shutil.copytree(cache_node_dir, to_dir)
529-
initialize_datadir(self.options.tmpdir, i) # Overwrite port/rpcport in bitcoin.conf
532+
initialize_datadir(self.options.tmpdir, i, self.chain) # Overwrite port/rpcport in bitcoin.conf
530533

531534
def _initialize_chain_clean(self):
532535
"""Initialize empty blockchain for use by the test.
533536
534537
Create an empty blockchain and num_nodes wallets.
535538
Useful if a test case wants complete control over initialization."""
536539
for i in range(self.num_nodes):
537-
initialize_datadir(self.options.tmpdir, i)
540+
initialize_datadir(self.options.tmpdir, i, self.chain)
538541

539542
def skip_if_no_py3_zmq(self):
540543
"""Attempt to import the zmq package and skip the test if the import fails."""

test/functional/test_framework/test_node.py

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

62-
def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False):
62+
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):
6363
"""
6464
Kwargs:
6565
start_perf (bool): If True, begin profiling the node with `perf` as soon as
@@ -70,6 +70,7 @@ def __init__(self, i, datadir, *, rpchost, timewait, bitcoind, bitcoin_cli, cove
7070
self.datadir = datadir
7171
self.stdout_dir = os.path.join(self.datadir, "stdout")
7272
self.stderr_dir = os.path.join(self.datadir, "stderr")
73+
self.chain = chain
7374
self.rpchost = rpchost
7475
self.rpc_timeout = timewait
7576
self.binary = bitcoind
@@ -197,7 +198,7 @@ def start(self, extra_args=None, *, cwd=None, stdout=None, stderr=None, **kwargs
197198
# Delete any existing cookie file -- if such a file exists (eg due to
198199
# unclean shutdown), it will get overwritten anyway by bitcoind, and
199200
# potentially interfere with our attempt to authenticate
200-
delete_cookie_file(self.datadir)
201+
delete_cookie_file(self.datadir, self.chain)
201202

202203
# add environment variable LIBC_FATAL_STDERR_=1 so that libc errors are written to stderr and not the terminal
203204
subp_env = dict(os.environ, LIBC_FATAL_STDERR_="1")
@@ -219,7 +220,7 @@ def wait_for_rpc_connection(self):
219220
raise FailedToStartError(self._node_msg(
220221
'bitcoind exited with status {} during initialization'.format(self.process.returncode)))
221222
try:
222-
rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir)
223+
rpc = get_rpc_proxy(rpc_url(self.datadir, self.index, self.chain, self.rpchost), self.index, timeout=self.rpc_timeout, coveragedir=self.coverage_dir)
223224
rpc.getblockcount()
224225
# If the call to getblockcount() succeeds then the RPC connection is up
225226
self.log.debug("RPC successfully started")
@@ -306,7 +307,7 @@ def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
306307

307308
@contextlib.contextmanager
308309
def assert_debug_log(self, expected_msgs):
309-
debug_log = os.path.join(self.datadir, 'regtest', 'debug.log')
310+
debug_log = os.path.join(self.datadir, self.chain, 'debug.log')
310311
with open(debug_log, encoding='utf-8') as dl:
311312
dl.seek(0, 2)
312313
prev_size = dl.tell()

test/functional/test_framework/util.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ def p2p_port(n):
271271
def rpc_port(n):
272272
return PORT_MIN + PORT_RANGE + n + (MAX_NODES * PortSeed.n) % (PORT_RANGE - 1 - MAX_NODES)
273273

274-
def rpc_url(datadir, i, rpchost=None):
275-
rpc_u, rpc_p = get_auth_cookie(datadir)
274+
def rpc_url(datadir, i, chain, rpchost):
275+
rpc_u, rpc_p = get_auth_cookie(datadir, chain)
276276
host = '127.0.0.1'
277277
port = rpc_port(i)
278278
if rpchost:
@@ -286,13 +286,13 @@ def rpc_url(datadir, i, rpchost=None):
286286
# Node functions
287287
################
288288

289-
def initialize_datadir(dirname, n):
289+
def initialize_datadir(dirname, n, chain):
290290
datadir = get_datadir_path(dirname, n)
291291
if not os.path.isdir(datadir):
292292
os.makedirs(datadir)
293293
with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f:
294-
f.write("regtest=1\n")
295-
f.write("[regtest]\n")
294+
f.write("{}=1\n".format(chain))
295+
f.write("[{}]\n".format(chain))
296296
f.write("port=" + str(p2p_port(n)) + "\n")
297297
f.write("rpcport=" + str(rpc_port(n)) + "\n")
298298
f.write("server=1\n")
@@ -312,7 +312,7 @@ def append_config(datadir, options):
312312
for option in options:
313313
f.write(option + "\n")
314314

315-
def get_auth_cookie(datadir):
315+
def get_auth_cookie(datadir, chain):
316316
user = None
317317
password = None
318318
if os.path.isfile(os.path.join(datadir, "bitcoin.conf")):
@@ -325,7 +325,7 @@ def get_auth_cookie(datadir):
325325
assert password is None # Ensure that there is only one rpcpassword line
326326
password = line.split("=")[1].strip("\n")
327327
try:
328-
with open(os.path.join(datadir, "regtest", ".cookie"), 'r', encoding="ascii") as f:
328+
with open(os.path.join(datadir, chain, ".cookie"), 'r', encoding="ascii") as f:
329329
userpass = f.read()
330330
split_userpass = userpass.split(':')
331331
user = split_userpass[0]
@@ -337,10 +337,10 @@ def get_auth_cookie(datadir):
337337
return user, password
338338

339339
# If a cookie file exists in the given datadir, delete it.
340-
def delete_cookie_file(datadir):
341-
if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")):
340+
def delete_cookie_file(datadir, chain):
341+
if os.path.isfile(os.path.join(datadir, chain, ".cookie")):
342342
logger.debug("Deleting leftover cookie file")
343-
os.remove(os.path.join(datadir, "regtest", ".cookie"))
343+
os.remove(os.path.join(datadir, chain, ".cookie"))
344344

345345
def get_bip9_status(node, key):
346346
info = node.getblockchaininfo()

0 commit comments

Comments
 (0)