Changeset View
Changeset View
Standalone View
Standalone View
test/functional/test_runner.py
Show First 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | BASE_SCRIPTS = [ | ||||
'nulldummy.py', | 'nulldummy.py', | ||||
'import-rescan.py', | 'import-rescan.py', | ||||
'mining.py', | 'mining.py', | ||||
'rpcnamedargs.py', | 'rpcnamedargs.py', | ||||
'listsinceblock.py', | 'listsinceblock.py', | ||||
'p2p-leaktests.py', | 'p2p-leaktests.py', | ||||
'abc-cmdline.py', | 'abc-cmdline.py', | ||||
'abc-p2p-fullblocktest.py', | 'abc-p2p-fullblocktest.py', | ||||
'abc-ebp.py', | |||||
'abc-rpc.py', | 'abc-rpc.py', | ||||
'abc-high_priority_transaction.py', | 'abc-high_priority_transaction.py', | ||||
'abc-mempool-accept-txn.py', | 'abc-mempool-accept-txn.py', | ||||
'wallet-encryption.py', | 'wallet-encryption.py', | ||||
'bipdersig-p2p.py', | 'bipdersig-p2p.py', | ||||
'bip65-cltv-p2p.py', | 'bip65-cltv-p2p.py', | ||||
'uptime.py', | 'uptime.py', | ||||
'resendwallettransactions.py', | 'resendwallettransactions.py', | ||||
Show All 27 Lines | EXTENDED_SCRIPTS = [ | ||||
'p2p-acceptblock.py', | 'p2p-acceptblock.py', | ||||
] | ] | ||||
# Place EXTENDED_SCRIPTS first since it has the 3 longest running tests | # Place EXTENDED_SCRIPTS first since it has the 3 longest running tests | ||||
ALL_SCRIPTS = EXTENDED_SCRIPTS + BASE_SCRIPTS | ALL_SCRIPTS = EXTENDED_SCRIPTS + BASE_SCRIPTS | ||||
NON_SCRIPTS = [ | NON_SCRIPTS = [ | ||||
# These are python files that live in the functional tests directory, but are not test scripts. | # These are python files that live in the functional tests directory, but | ||||
# are not test scripts. | |||||
"combine_logs.py", | "combine_logs.py", | ||||
"create_cache.py", | "create_cache.py", | ||||
"test_runner.py", | "test_runner.py", | ||||
] | ] | ||||
def on_ci(): | def on_ci(): | ||||
return os.getenv('TRAVIS') == 'true' or os.getenv('TEAMCITY_VERSION') != None | return os.getenv('TRAVIS') == 'true' or os.getenv('TEAMCITY_VERSION') != None | ||||
▲ Show 20 Lines • Show All 260 Lines • ▼ Show 20 Lines | def get_next(self): | ||||
portseed_arg = ["--portseed={}".format(portseed)] | portseed_arg = ["--portseed={}".format(portseed)] | ||||
log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) | log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) | ||||
log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) | log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) | ||||
test_argv = t.split() | test_argv = t.split() | ||||
tmpdir = [os.path.join("--tmpdir=%s", "%s_%s") % | tmpdir = [os.path.join("--tmpdir=%s", "%s_%s") % | ||||
(self.tmpdir, re.sub(".py$", "", t), portseed)] | (self.tmpdir, re.sub(".py$", "", t), portseed)] | ||||
self.jobs.append((t, | self.jobs.append((t, | ||||
time.time(), | time.time(), | ||||
subprocess.Popen([os.path.join(self.tests_dir, test_argv[0])] + test_argv[1:] + self.flags + portseed_arg + tmpdir, | subprocess.Popen( | ||||
[os.path.join(self.tests_dir, test_argv[0])] + test_argv[ | |||||
1:] + self.flags + portseed_arg + tmpdir, | |||||
universal_newlines=True, | universal_newlines=True, | ||||
stdout=log_stdout, | stdout=log_stdout, | ||||
stderr=log_stderr), | stderr=log_stderr), | ||||
log_stdout, | log_stdout, | ||||
log_stderr)) | log_stderr)) | ||||
if not self.jobs: | if not self.jobs: | ||||
raise IndexError('pop from empty list') | raise IndexError('pop from empty list') | ||||
while True: | while True: | ||||
# Return first proc that finishes | # Return first proc that finishes | ||||
time.sleep(.5) | time.sleep(.5) | ||||
for j in self.jobs: | for j in self.jobs: | ||||
(name, time0, proc, log_out, log_err) = j | (name, time0, proc, log_out, log_err) = j | ||||
Show All 15 Lines | def get_next(self): | ||||
self.num_running -= 1 | self.num_running -= 1 | ||||
self.jobs.remove(j) | self.jobs.remove(j) | ||||
return TestResult(name, status, int(time.time() - time0), stdout, stderr) | return TestResult(name, status, int(time.time() - time0), stdout, stderr) | ||||
print('.', end='', flush=True) | print('.', end='', flush=True) | ||||
class TestResult(): | class TestResult(): | ||||
def __init__(self, name, status, time, stdout, stderr): | def __init__(self, name, status, time, stdout, stderr): | ||||
self.name = name | self.name = name | ||||
self.status = status | self.status = status | ||||
self.time = time | self.time = time | ||||
self.padding = 0 | self.padding = 0 | ||||
self.stdout = stdout | self.stdout = stdout | ||||
self.stderr = stderr | self.stderr = stderr | ||||
Show All 19 Lines | def check_script_list(src_dir): | ||||
script_dir = os.path.join(src_dir, 'test', 'functional') | script_dir = os.path.join(src_dir, 'test', 'functional') | ||||
python_files = set([t for t in os.listdir(script_dir) if t[-3:] == ".py"]) | python_files = set([t for t in os.listdir(script_dir) if t[-3:] == ".py"]) | ||||
missed_tests = list( | missed_tests = list( | ||||
python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS))) | python_files - set(map(lambda x: x.split()[0], ALL_SCRIPTS + NON_SCRIPTS))) | ||||
if len(missed_tests) != 0: | if len(missed_tests) != 0: | ||||
print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % ( | print("%sWARNING!%s The following scripts are not being run: %s. Check the test lists in test_runner.py." % ( | ||||
BOLD[1], BOLD[0], str(missed_tests))) | BOLD[1], BOLD[0], str(missed_tests))) | ||||
if on_ci(): | if on_ci(): | ||||
# On CI this warning is an error to prevent merging incomplete commits into master | # On CI this warning is an error to prevent merging incomplete | ||||
# commits into master | |||||
sys.exit(1) | sys.exit(1) | ||||
class RPCCoverage(): | class RPCCoverage(): | ||||
""" | """ | ||||
Coverage reporting utilities for test_runner. | Coverage reporting utilities for test_runner. | ||||
Coverage calculation works by having each test script subprocess write | Coverage calculation works by having each test script subprocess write | ||||
coverage files into a particular directory. These files contain the RPC | coverage files into a particular directory. These files contain the RPC | ||||
commands invoked during testing, as well as a complete listing of RPC | commands invoked during testing, as well as a complete listing of RPC | ||||
commands per `bitcoin-cli help` (`rpc_interface.txt`). | commands per `bitcoin-cli help` (`rpc_interface.txt`). | ||||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | for test_result in test_results: | ||||
ET.SubElement(e_test_case, "system-out").text = test_result.stdout | ET.SubElement(e_test_case, "system-out").text = test_result.stdout | ||||
ET.SubElement(e_test_case, "system-err").text = test_result.stderr | ET.SubElement(e_test_case, "system-err").text = test_result.stderr | ||||
ET.ElementTree(e_test_suite).write( | ET.ElementTree(e_test_suite).write( | ||||
file_name, "UTF-8", xml_declaration=True) | file_name, "UTF-8", xml_declaration=True) | ||||
class Timings(): | class Timings(): | ||||
""" | """ | ||||
Takes care of loading, merging and saving tests execution times. | Takes care of loading, merging and saving tests execution times. | ||||
""" | """ | ||||
def __init__(self, dir): | def __init__(self, dir): | ||||
self.dir = dir | self.dir = dir | ||||
self.timing_file = os.path.join(dir, 'timing.json') | self.timing_file = os.path.join(dir, 'timing.json') | ||||
self.existing_timings = self.load_timings() | self.existing_timings = self.load_timings() | ||||
Show All 40 Lines |