Skip to content

Commit 7ff4a53

Browse files
author
MarcoFalke
committed
Merge #9657: Improve rpc-tests.py
a6a3e58 Various review markups for rpc-tests.py improvements (John Newbery) 3de3ccd Refactor rpc-tests.py (John Newbery) afd38e7 Improve rpc-tests.py arguments (John Newbery) 91bffff Use argparse in rpc_tests.py (John Newbery) 1581ecb Use configparser in rpc-tests.py (John Newbery)
2 parents aa5fa64 + a6a3e58 commit 7ff4a53

File tree

5 files changed

+152
-134
lines changed

5 files changed

+152
-134
lines changed

Makefile.am

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,6 @@ EXTRA_DIST = $(top_srcdir)/share/genbuild.sh qa/pull-tester/rpc-tests.py qa/rpc-
227227

228228
CLEANFILES = $(OSX_DMG) $(BITCOIN_WIN_INSTALLER)
229229

230-
# This file is problematic for out-of-tree builds if it exists.
231-
DISTCLEANFILES = qa/pull-tester/tests_config.pyc
232-
233230
.INTERMEDIATE: $(COVERAGE_INFO)
234231

235232
DISTCHECK_CONFIGURE_FLAGS = --enable-man

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,7 @@ AC_SUBST(ZMQ_LIBS)
10871087
AC_SUBST(PROTOBUF_LIBS)
10881088
AC_SUBST(QR_LIBS)
10891089
AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile share/setup.nsi share/qt/Info.plist src/test/buildenv.py])
1090-
AC_CONFIG_FILES([qa/pull-tester/tests_config.py],[chmod +x qa/pull-tester/tests_config.py])
1090+
AC_CONFIG_FILES([qa/pull-tester/tests_config.ini],[chmod +x qa/pull-tester/tests_config.ini])
10911091
AC_CONFIG_FILES([contrib/devtools/split-debug.sh],[chmod +x contrib/devtools/split-debug.sh])
10921092
AC_CONFIG_LINKS([qa/pull-tester/rpc-tests.py:qa/pull-tester/rpc-tests.py])
10931093

qa/pull-tester/rpc-tests.py

Lines changed: 133 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,21 @@
22
# Copyright (c) 2014-2016 The Bitcoin Core developers
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5-
65
"""
7-
Run Regression Test Suite
6+
rpc-tests.py - run regression test suite
87
98
This module calls down into individual test cases via subprocess. It will
10-
forward all unrecognized arguments onto the individual test scripts, other
11-
than:
9+
forward all unrecognized arguments onto the individual test scripts.
1210
13-
- `-extended`: run the "extended" test suite in addition to the basic one.
14-
- `-win`: signal that this is running in a Windows environment, and we
15-
should run the tests.
16-
- `--coverage`: this generates a basic coverage report for the RPC
17-
interface.
11+
RPC tests are disabled on Windows by default. Use --force to run them anyway.
1812
1913
For a description of arguments recognized by test scripts, see
2014
`qa/pull-tester/test_framework/test_framework.py:BitcoinTestFramework.main`.
2115
2216
"""
2317

18+
import argparse
19+
import configparser
2420
import os
2521
import time
2622
import shutil
@@ -29,77 +25,9 @@
2925
import tempfile
3026
import re
3127

32-
sys.path.append("qa/pull-tester/")
33-
from tests_config import *
34-
35-
BOLD = ("","")
36-
if os.name == 'posix':
37-
# primitive formatting on supported
38-
# terminal via ANSI escape sequences:
39-
BOLD = ('\033[0m', '\033[1m')
40-
41-
RPC_TESTS_DIR = SRCDIR + '/qa/rpc-tests/'
42-
43-
#If imported values are not defined then set to zero (or disabled)
44-
if 'ENABLE_WALLET' not in vars():
45-
ENABLE_WALLET=0
46-
if 'ENABLE_BITCOIND' not in vars():
47-
ENABLE_BITCOIND=0
48-
if 'ENABLE_UTILS' not in vars():
49-
ENABLE_UTILS=0
50-
if 'ENABLE_ZMQ' not in vars():
51-
ENABLE_ZMQ=0
52-
53-
ENABLE_COVERAGE=0
54-
55-
#Create a set to store arguments and create the passon string
56-
opts = set()
57-
passon_args = []
58-
PASSON_REGEX = re.compile("^--")
59-
PARALLEL_REGEX = re.compile('^-parallel=')
60-
61-
print_help = False
62-
run_parallel = 4
63-
64-
for arg in sys.argv[1:]:
65-
if arg == "--help" or arg == "-h" or arg == "-?":
66-
print_help = True
67-
break
68-
if arg == '--coverage':
69-
ENABLE_COVERAGE = 1
70-
elif PASSON_REGEX.match(arg):
71-
passon_args.append(arg)
72-
elif PARALLEL_REGEX.match(arg):
73-
run_parallel = int(arg.split(sep='=', maxsplit=1)[1])
74-
else:
75-
opts.add(arg)
76-
77-
#Set env vars
78-
if "BITCOIND" not in os.environ:
79-
os.environ["BITCOIND"] = BUILDDIR + '/src/bitcoind' + EXEEXT
80-
81-
if EXEEXT == ".exe" and "-win" not in opts:
82-
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
83-
# https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
84-
print("Win tests currently disabled by default. Use -win option to enable")
85-
sys.exit(0)
86-
87-
if not (ENABLE_WALLET == 1 and ENABLE_UTILS == 1 and ENABLE_BITCOIND == 1):
88-
print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
89-
sys.exit(0)
90-
91-
# python3-zmq may not be installed. Handle this gracefully and with some helpful info
92-
if ENABLE_ZMQ:
93-
try:
94-
import zmq
95-
except ImportError:
96-
print("ERROR: \"import zmq\" failed. Set ENABLE_ZMQ=0 or "
97-
"to run zmq tests, see dependency info in /qa/README.md.")
98-
# ENABLE_ZMQ=0
99-
raise
100-
101-
testScripts = [
102-
# longest test should go first, to favor running tests in parallel
28+
BASE_SCRIPTS= [
29+
# Scripts that are run by the travis build process.
30+
# Longest test should go first, to favor running tests in parallel
10331
'wallet-hd.py',
10432
'walletbackup.py',
10533
# vv Tests less than 5m vv
@@ -156,10 +84,15 @@
15684
'listsinceblock.py',
15785
'p2p-leaktests.py',
15886
]
159-
if ENABLE_ZMQ:
160-
testScripts.append('zmq_test.py')
16187

162-
testScriptsExt = [
88+
ZMQ_SCRIPTS = [
89+
# ZMQ test can only be run if bitcoin was built with zmq-enabled.
90+
# call rpc_tests.py with -nozmq to explicitly exclude these tests.
91+
"zmq_test.py"]
92+
93+
EXTENDED_SCRIPTS = [
94+
# These tests are not run by the travis build process.
95+
# Longest test should go first, to favor running tests in parallel
16396
'pruning.py',
16497
# vv Tests less than 20m vv
16598
'smartfees.py',
@@ -189,44 +122,126 @@
189122
'replace-by-fee.py',
190123
]
191124

125+
ALL_SCRIPTS = BASE_SCRIPTS + ZMQ_SCRIPTS + EXTENDED_SCRIPTS
126+
127+
def main():
128+
# Parse arguments and pass through unrecognised args
129+
parser = argparse.ArgumentParser(add_help=False,
130+
usage='%(prog)s [rpc-test.py options] [script options] [scripts]',
131+
description=__doc__,
132+
epilog='''
133+
Help text and arguments for individual test script:''',
134+
formatter_class=argparse.RawTextHelpFormatter)
135+
parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface')
136+
parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests')
137+
parser.add_argument('--force', '-f', action='store_true', help='run tests even on platforms where they are disabled by default (e.g. windows).')
138+
parser.add_argument('--help', '-h', '-?', action='store_true', help='print help text and exit')
139+
parser.add_argument('--jobs', '-j', type=int, default=4, help='how many test scripts to run in parallel. Default=4.')
140+
parser.add_argument('--nozmq', action='store_true', help='do not run the zmq tests')
141+
args, unknown_args = parser.parse_known_args()
142+
143+
# Create a set to store arguments and create the passon string
144+
tests = set(arg for arg in unknown_args if arg[:2] != "--")
145+
passon_args = [arg for arg in unknown_args if arg[:2] == "--"]
146+
147+
# Read config generated by configure.
148+
config = configparser.ConfigParser()
149+
config.read_file(open(os.path.dirname(__file__) + "/tests_config.ini"))
150+
151+
enable_wallet = config["components"].getboolean("ENABLE_WALLET")
152+
enable_utils = config["components"].getboolean("ENABLE_UTILS")
153+
enable_bitcoind = config["components"].getboolean("ENABLE_BITCOIND")
154+
enable_zmq = config["components"].getboolean("ENABLE_ZMQ") and not args.nozmq
155+
156+
if config["environment"]["EXEEXT"] == ".exe" and not args.force:
157+
# https://github.com/bitcoin/bitcoin/commit/d52802551752140cf41f0d9a225a43e84404d3e9
158+
# https://github.com/bitcoin/bitcoin/pull/5677#issuecomment-136646964
159+
print("Tests currently disabled on Windows by default. Use --force option to enable")
160+
sys.exit(0)
192161

193-
def runtests():
194-
test_list = []
195-
if '-extended' in opts:
196-
test_list = testScripts + testScriptsExt
197-
elif len(opts) == 0 or (len(opts) == 1 and "-win" in opts):
198-
test_list = testScripts
199-
else:
200-
for t in testScripts + testScriptsExt:
201-
if t in opts or re.sub(".py$", "", t) in opts:
202-
test_list.append(t)
162+
if not (enable_wallet and enable_utils and enable_bitcoind):
163+
print("No rpc tests to run. Wallet, utils, and bitcoind must all be enabled")
164+
print("Rerun `configure` with -enable-wallet, -with-utils and -with-daemon and rerun make")
165+
sys.exit(0)
166+
167+
# python3-zmq may not be installed. Handle this gracefully and with some helpful info
168+
if enable_zmq:
169+
try:
170+
import zmq
171+
except ImportError:
172+
print("ERROR: \"import zmq\" failed. Use -nozmq to run without the ZMQ tests."
173+
"To run zmq tests, see dependency info in /qa/README.md.")
174+
raise
175+
176+
# Build list of tests
177+
if tests:
178+
# Individual tests have been specified. Run specified tests that exist
179+
# in the ALL_SCRIPTS list. Accept the name with or without .py extension.
180+
test_list = [t for t in ALL_SCRIPTS if
181+
(t in tests or re.sub(".py$", "", t) in tests)]
182+
if not test_list:
183+
print("No valid test scripts specified. Check that your test is in one "
184+
"of the test lists in rpc-tests.py or run rpc-tests.py with no arguments to run all tests")
185+
print("Scripts not found:")
186+
print(tests)
187+
sys.exit(0)
203188

204-
if print_help:
205-
# Only print help of the first script and exit
206-
subprocess.check_call((RPC_TESTS_DIR + test_list[0]).split() + ['-h'])
189+
else:
190+
# No individual tests have been specified. Run base tests, and
191+
# optionally ZMQ tests and extended tests.
192+
test_list = BASE_SCRIPTS
193+
if enable_zmq:
194+
test_list += ZMQ_SCRIPTS
195+
if args.extended:
196+
test_list += EXTENDED_SCRIPTS
197+
# TODO: BASE_SCRIPTS and EXTENDED_SCRIPTS are sorted by runtime
198+
# (for parallel running efficiency). This combined list will is no
199+
# longer sorted.
200+
201+
if args.help:
202+
# Print help for rpc-tests.py, then print help of the first script and exit.
203+
parser.print_help()
204+
subprocess.check_call((config["environment"]["SRCDIR"] + '/qa/rpc-tests/' + test_list[0]).split() + ['-h'])
207205
sys.exit(0)
208206

209-
coverage = None
207+
run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], args.jobs, args.coverage, passon_args)
208+
209+
def run_tests(test_list, src_dir, build_dir, exeext, jobs=1, enable_coverage=False, args=[]):
210+
BOLD = ("","")
211+
if os.name == 'posix':
212+
# primitive formatting on supported
213+
# terminal via ANSI escape sequences:
214+
BOLD = ('\033[0m', '\033[1m')
215+
216+
#Set env vars
217+
if "BITCOIND" not in os.environ:
218+
os.environ["BITCOIND"] = build_dir + '/src/bitcoind' + exeext
219+
220+
tests_dir = src_dir + '/qa/rpc-tests/'
210221

211-
if ENABLE_COVERAGE:
222+
flags = ["--srcdir=" + src_dir] + args
223+
flags.append("--cachedir=%s/qa/cache" % build_dir)
224+
225+
if enable_coverage:
212226
coverage = RPCCoverage()
213-
print("Initializing coverage directory at %s\n" % coverage.dir)
214-
flags = ["--srcdir=%s/src" % BUILDDIR] + passon_args
215-
flags.append("--cachedir=%s/qa/cache" % BUILDDIR)
216-
if coverage:
217227
flags.append(coverage.flag)
228+
print("Initializing coverage directory at %s\n" % coverage.dir)
229+
else:
230+
coverage = None
218231

219-
if len(test_list) > 1 and run_parallel > 1:
232+
if len(test_list) > 1 and jobs > 1:
220233
# Populate cache
221-
subprocess.check_output([RPC_TESTS_DIR + 'create_cache.py'] + flags)
234+
subprocess.check_output([tests_dir + 'create_cache.py'] + flags)
222235

223236
#Run Tests
224-
max_len_name = len(max(test_list, key=len))
237+
all_passed = True
225238
time_sum = 0
226239
time0 = time.time()
227-
job_queue = RPCTestHandler(run_parallel, test_list, flags)
240+
241+
job_queue = RPCTestHandler(jobs, tests_dir, test_list, flags)
242+
243+
max_len_name = len(max(test_list, key=len))
228244
results = BOLD[1] + "%s | %s | %s\n\n" % ("TEST".ljust(max_len_name), "PASSED", "DURATION") + BOLD[0]
229-
all_passed = True
230245
for _ in range(len(test_list)):
231246
(name, stdout, stderr, passed, duration) = job_queue.get_next()
232247
all_passed = all_passed and passed
@@ -235,8 +250,10 @@ def runtests():
235250
print('\n' + BOLD[1] + name + BOLD[0] + ":")
236251
print('' if passed else stdout + '\n', end='')
237252
print('' if stderr == '' else 'stderr:\n' + stderr + '\n', end='')
238-
results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
239253
print("Pass: %s%s%s, Duration: %s s\n" % (BOLD[1], passed, BOLD[0], duration))
254+
255+
results += "%s | %s | %s s\n" % (name.ljust(max_len_name), str(passed).ljust(6), duration)
256+
240257
results += BOLD[1] + "\n%s | %s | %s s (accumulated)" % ("ALL".ljust(max_len_name), str(all_passed).ljust(6), time_sum) + BOLD[0]
241258
print(results)
242259
print("\nRuntime: %s s" % (int(time.time() - time0)))
@@ -249,15 +266,15 @@ def runtests():
249266

250267
sys.exit(not all_passed)
251268

252-
253269
class RPCTestHandler:
254270
"""
255271
Trigger the testscrips passed in via the list.
256272
"""
257273

258-
def __init__(self, num_tests_parallel, test_list=None, flags=None):
274+
def __init__(self, num_tests_parallel, tests_dir, test_list=None, flags=None):
259275
assert(num_tests_parallel >= 1)
260276
self.num_jobs = num_tests_parallel
277+
self.tests_dir = tests_dir
261278
self.test_list = test_list
262279
self.flags = flags
263280
self.num_running = 0
@@ -277,7 +294,7 @@ def get_next(self):
277294
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16)
278295
self.jobs.append((t,
279296
time.time(),
280-
subprocess.Popen((RPC_TESTS_DIR + t).split() + self.flags + port_seed,
297+
subprocess.Popen((self.tests_dir + t).split() + self.flags + port_seed,
281298
universal_newlines=True,
282299
stdout=log_stdout,
283300
stderr=log_stderr),
@@ -342,10 +359,10 @@ def _get_uncovered_rpc_commands(self):
342359
343360
"""
344361
# This is shared from `qa/rpc-tests/test-framework/coverage.py`
345-
REFERENCE_FILENAME = 'rpc_interface.txt'
346-
COVERAGE_FILE_PREFIX = 'coverage.'
362+
reference_filename = 'rpc_interface.txt'
363+
coverage_file_prefix = 'coverage.'
347364

348-
coverage_ref_filename = os.path.join(self.dir, REFERENCE_FILENAME)
365+
coverage_ref_filename = os.path.join(self.dir, reference_filename)
349366
coverage_filenames = set()
350367
all_cmds = set()
351368
covered_cmds = set()
@@ -358,7 +375,7 @@ def _get_uncovered_rpc_commands(self):
358375

359376
for root, dirs, files in os.walk(self.dir):
360377
for filename in files:
361-
if filename.startswith(COVERAGE_FILE_PREFIX):
378+
if filename.startswith(coverage_file_prefix):
362379
coverage_filenames.add(os.path.join(root, filename))
363380

364381
for filename in coverage_filenames:
@@ -369,4 +386,4 @@ def _get_uncovered_rpc_commands(self):
369386

370387

371388
if __name__ == '__main__':
372-
runtests()
389+
main()

qa/pull-tester/tests_config.ini.in

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright (c) 2013-2016 The Bitcoin Core developers
2+
# Distributed under the MIT software license, see the accompanying
3+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
# These environment variables are set by the build process and read by
6+
# rpc-tests.py
7+
8+
[environment]
9+
SRCDIR=@abs_top_srcdir@
10+
BUILDDIR=@abs_top_builddir@
11+
EXEEXT=@EXEEXT@
12+
13+
[components]
14+
# Which components are enabled. These are commented out by `configure` if they were disabled when running config.
15+
@ENABLE_WALLET_TRUE@ENABLE_WALLET=true
16+
@BUILD_BITCOIN_UTILS_TRUE@ENABLE_UTILS=true
17+
@BUILD_BITCOIND_TRUE@ENABLE_BITCOIND=true
18+
@ENABLE_ZMQ_TRUE@ENABLE_ZMQ=true

0 commit comments

Comments
 (0)