diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/functional/README.md | 10 | ||||
-rwxr-xr-x | test/functional/assumevalid.py | 4 | ||||
-rwxr-xr-x | test/functional/bip65-cltv-p2p.py | 2 | ||||
-rwxr-xr-x | test/functional/bipdersig-p2p.py | 2 | ||||
-rwxr-xr-x | test/functional/example_test.py | 21 | ||||
-rwxr-xr-x | test/functional/maxuploadtarget.py | 2 | ||||
-rwxr-xr-x | test/functional/p2p-acceptblock.py | 12 | ||||
-rwxr-xr-x | test/functional/p2p-compactblocks.py | 2 | ||||
-rwxr-xr-x | test/functional/p2p-feefilter.py | 2 | ||||
-rwxr-xr-x | test/functional/p2p-fingerprint.py | 4 | ||||
-rwxr-xr-x | test/functional/p2p-leaktests.py | 8 | ||||
-rwxr-xr-x | test/functional/p2p-mempool.py | 2 | ||||
-rwxr-xr-x | test/functional/p2p-segwit.py | 2 | ||||
-rwxr-xr-x | test/functional/p2p-timeouts.py | 2 | ||||
-rwxr-xr-x | test/functional/p2p-versionbits-warning.py | 2 | ||||
-rwxr-xr-x | test/functional/sendheaders.py | 4 | ||||
-rwxr-xr-x | test/functional/test_framework/comptool.py | 2 | ||||
-rwxr-xr-x | test/functional/test_framework/mininode.py | 22 | ||||
-rwxr-xr-x | test/functional/test_framework/test_framework.py | 26 | ||||
-rwxr-xr-x | test/functional/test_runner.py | 26 |
20 files changed, 75 insertions, 82 deletions
diff --git a/test/functional/README.md b/test/functional/README.md index 2558bd017d..193ca947bc 100644 --- a/test/functional/README.md +++ b/test/functional/README.md @@ -63,12 +63,12 @@ wrappers for them, `msg_block`, `msg_tx`, etc). with the bitcoind(s) being tested (using python's asyncore package); the other implements the test logic. -- `NodeConn` is the class used to connect to a bitcoind. If you implement -a callback class that derives from `NodeConnCB` and pass that to the -`NodeConn` object, your code will receive the appropriate callbacks when -events of interest arrive. +- `P2PConnection` is the class used to connect to a bitcoind. `P2PInterface` +contains the higher level logic for processing P2P payloads and connecting to +the Bitcoin Core node application logic. For custom behaviour, subclass the +P2PInterface object and override the callback methods. -- Call `NetworkThread.start()` after all `NodeConn` objects are created to +- Call `NetworkThread.start()` after all `P2PInterface` objects are created to start the networking thread. (Continue with the test logic in your existing thread.) diff --git a/test/functional/assumevalid.py b/test/functional/assumevalid.py index 72da955641..13104f71bc 100755 --- a/test/functional/assumevalid.py +++ b/test/functional/assumevalid.py @@ -39,14 +39,14 @@ from test_framework.mininode import (CBlockHeader, CTxIn, CTxOut, NetworkThread, - NodeConnCB, + P2PInterface, msg_block, msg_headers) from test_framework.script import (CScript, OP_TRUE) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal -class BaseNode(NodeConnCB): +class BaseNode(P2PInterface): def send_header_for_blocks(self, new_blocks): headers_message = msg_headers() headers_message.headers = [CBlockHeader(b) for b in new_blocks] diff --git a/test/functional/bip65-cltv-p2p.py b/test/functional/bip65-cltv-p2p.py index 3073324798..2af5eb275f 100755 --- a/test/functional/bip65-cltv-p2p.py +++ b/test/functional/bip65-cltv-p2p.py @@ -66,7 +66,7 @@ class BIP65Test(BitcoinTestFramework): self.setup_clean_chain = True def run_test(self): - self.nodes[0].add_p2p_connection(NodeConnCB()) + self.nodes[0].add_p2p_connection(P2PInterface()) NetworkThread().start() # Start up network handling in another thread diff --git a/test/functional/bipdersig-p2p.py b/test/functional/bipdersig-p2p.py index e5febde42d..7a3e565e2c 100755 --- a/test/functional/bipdersig-p2p.py +++ b/test/functional/bipdersig-p2p.py @@ -54,7 +54,7 @@ class BIP66Test(BitcoinTestFramework): self.setup_clean_chain = True def run_test(self): - self.nodes[0].add_p2p_connection(NodeConnCB()) + self.nodes[0].add_p2p_connection(P2PInterface()) NetworkThread().start() # Start up network handling in another thread diff --git a/test/functional/example_test.py b/test/functional/example_test.py index 54cabee51c..289fa248e0 100755 --- a/test/functional/example_test.py +++ b/test/functional/example_test.py @@ -18,10 +18,11 @@ from test_framework.blocktools import (create_block, create_coinbase) from test_framework.mininode import ( CInv, NetworkThread, - NodeConnCB, + P2PInterface, mininode_lock, msg_block, msg_getdata, + NODE_NETWORK, ) from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( @@ -30,15 +31,15 @@ from test_framework.util import ( wait_until, ) -# NodeConnCB is a class containing callbacks to be executed when a P2P -# message is received from the node-under-test. Subclass NodeConnCB and +# P2PInterface is a class containing callbacks to be executed when a P2P +# message is received from the node-under-test. Subclass P2PInterface and # override the on_*() methods if you need custom behaviour. -class BaseNode(NodeConnCB): +class BaseNode(P2PInterface): def __init__(self): - """Initialize the NodeConnCB + """Initialize the P2PInterface Used to inialize custom properties for the Node that aren't - included by default in the base class. Be aware that the NodeConnCB + included by default in the base class. Be aware that the P2PInterface base class already stores a counter for each P2P message type and the last received message of each type, which should be sufficient for the needs of most tests. @@ -174,7 +175,7 @@ class ExampleTest(BitcoinTestFramework): block = create_block(self.tip, create_coinbase(height), self.block_time) block.solve() block_message = msg_block(block) - # Send message is used to send a P2P message to the node over our NodeConn connection + # Send message is used to send a P2P message to the node over our P2PInterface self.nodes[0].p2p.send_message(block_message) self.tip = block.sha256 blocks.append(self.tip) @@ -199,12 +200,12 @@ class ExampleTest(BitcoinTestFramework): self.nodes[2].p2p.send_message(getdata_request) # wait_until() will loop until a predicate condition is met. Use it to test properties of the - # NodeConnCB objects. + # P2PInterface objects. wait_until(lambda: sorted(blocks) == sorted(list(self.nodes[2].p2p.block_receive_map.keys())), timeout=5, lock=mininode_lock) self.log.info("Check that each block was received only once") - # The network thread uses a global lock on data access to the NodeConn objects when sending and receiving - # messages. The test thread should acquire the global lock before accessing any NodeConn data to avoid locking + # The network thread uses a global lock on data access to the P2PConnection objects when sending and receiving + # messages. The test thread should acquire the global lock before accessing any P2PConnection data to avoid locking # and synchronization issues. Note wait_until() acquires this global lock when testing the predicate. with mininode_lock: for block in self.nodes[2].p2p.block_receive_map.values(): diff --git a/test/functional/maxuploadtarget.py b/test/functional/maxuploadtarget.py index beb0d599d2..5ef71c93cf 100755 --- a/test/functional/maxuploadtarget.py +++ b/test/functional/maxuploadtarget.py @@ -17,7 +17,7 @@ from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -class TestNode(NodeConnCB): +class TestNode(P2PInterface): def __init__(self): super().__init__() self.block_receive_map = defaultdict(int) diff --git a/test/functional/p2p-acceptblock.py b/test/functional/p2p-acceptblock.py index ca0e0080a1..d9d7c24416 100755 --- a/test/functional/p2p-acceptblock.py +++ b/test/functional/p2p-acceptblock.py @@ -7,7 +7,7 @@ Setup: two nodes, node0+node1, not connected to each other. Node1 will have nMinimumChainWork set to 0x10, so it won't process low-work unrequested blocks. -We have one NodeConn connection to node0 called test_node, and one to node1 +We have one P2PInterface connection to node0 called test_node, and one to node1 called min_work_node. The test: @@ -79,9 +79,9 @@ class AcceptBlockTest(BitcoinTestFramework): def run_test(self): # Setup the p2p connections and start up the network thread. # test_node connects to node0 (not whitelisted) - test_node = self.nodes[0].add_p2p_connection(NodeConnCB()) - # min_work_node connects to node1 - min_work_node = self.nodes[1].add_p2p_connection(NodeConnCB()) + test_node = self.nodes[0].add_p2p_connection(P2PInterface()) + # min_work_node connects to node1 (whitelisted) + min_work_node = self.nodes[1].add_p2p_connection(P2PInterface()) NetworkThread().start() # Start up network handling in another thread @@ -207,7 +207,7 @@ class AcceptBlockTest(BitcoinTestFramework): # disconnect/reconnect first self.nodes[0].disconnect_p2ps() - test_node = self.nodes[0].add_p2p_connection(NodeConnCB()) + test_node = self.nodes[0].add_p2p_connection(P2PInterface()) test_node.wait_for_verack() test_node.send_message(msg_block(block_h1f)) @@ -292,7 +292,7 @@ class AcceptBlockTest(BitcoinTestFramework): test_node.wait_for_disconnect() self.nodes[0].disconnect_p2ps() - test_node = self.nodes[0].add_p2p_connection(NodeConnCB()) + test_node = self.nodes[0].add_p2p_connection(P2PInterface()) NetworkThread().start() # Start up network handling in another thread test_node.wait_for_verack() diff --git a/test/functional/p2p-compactblocks.py b/test/functional/p2p-compactblocks.py index 5aba1db873..c43744328c 100755 --- a/test/functional/p2p-compactblocks.py +++ b/test/functional/p2p-compactblocks.py @@ -15,7 +15,7 @@ from test_framework.blocktools import create_block, create_coinbase, add_witness from test_framework.script import CScript, OP_TRUE # TestNode: A peer we use to send messages to bitcoind, and store responses. -class TestNode(NodeConnCB): +class TestNode(P2PInterface): def __init__(self): super().__init__() self.last_sendcmpct = [] diff --git a/test/functional/p2p-feefilter.py b/test/functional/p2p-feefilter.py index 0ce3c3f429..ac55336e3d 100755 --- a/test/functional/p2p-feefilter.py +++ b/test/functional/p2p-feefilter.py @@ -22,7 +22,7 @@ def allInvsMatch(invsExpected, testnode): time.sleep(1) return False -class TestNode(NodeConnCB): +class TestNode(P2PInterface): def __init__(self): super().__init__() self.txinvs = [] diff --git a/test/functional/p2p-fingerprint.py b/test/functional/p2p-fingerprint.py index a8ce68374c..209c789f22 100755 --- a/test/functional/p2p-fingerprint.py +++ b/test/functional/p2p-fingerprint.py @@ -14,7 +14,7 @@ from test_framework.blocktools import (create_block, create_coinbase) from test_framework.mininode import ( CInv, NetworkThread, - NodeConnCB, + P2PInterface, msg_headers, msg_block, msg_getdata, @@ -75,7 +75,7 @@ class P2PFingerprintTest(BitcoinTestFramework): # This does not currently test that stale blocks timestamped within the # last month but that have over a month's worth of work are also withheld. def run_test(self): - node0 = self.nodes[0].add_p2p_connection(NodeConnCB()) + node0 = self.nodes[0].add_p2p_connection(P2PInterface()) NetworkThread().start() node0.wait_for_verack() diff --git a/test/functional/p2p-leaktests.py b/test/functional/p2p-leaktests.py index 3634f3836d..b469a9a47a 100755 --- a/test/functional/p2p-leaktests.py +++ b/test/functional/p2p-leaktests.py @@ -20,7 +20,7 @@ from test_framework.util import * banscore = 10 -class CLazyNode(NodeConnCB): +class CLazyNode(P2PInterface): def __init__(self): super().__init__() self.unexpected_msg = False @@ -139,10 +139,10 @@ class P2PLeakTest(BitcoinTestFramework): self.log.info("Service bits 5 and 7 are allowed after August 1st 2018") self.nodes[0].setmocktime(1533168000) # August 2nd 2018 - allowed_service_bit5_node = self.nodes[0].add_p2p_connection(NodeConnCB(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5) - allowed_service_bit7_node = self.nodes[0].add_p2p_connection(NodeConnCB(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7) + allowed_service_bit5_node = self.nodes[0].add_p2p_connection(P2PInterface(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_5) + allowed_service_bit7_node = self.nodes[0].add_p2p_connection(P2PInterface(), services=NODE_NETWORK|NODE_UNSUPPORTED_SERVICE_BIT_7) - NetworkThread().start() # Network thread stopped when all previous NodeConnCBs disconnected. Restart it + NetworkThread().start() # Network thread stopped when all previous P2PInterfaces disconnected. Restart it wait_until(lambda: allowed_service_bit5_node.message_count["verack"], lock=mininode_lock) wait_until(lambda: allowed_service_bit7_node.message_count["verack"], lock=mininode_lock) diff --git a/test/functional/p2p-mempool.py b/test/functional/p2p-mempool.py index be467c4223..d24dbac51d 100755 --- a/test/functional/p2p-mempool.py +++ b/test/functional/p2p-mempool.py @@ -20,7 +20,7 @@ class P2PMempoolTests(BitcoinTestFramework): def run_test(self): # Add a p2p connection - self.nodes[0].add_p2p_connection(NodeConnCB()) + self.nodes[0].add_p2p_connection(P2PInterface()) NetworkThread().start() self.nodes[0].p2p.wait_for_verack() diff --git a/test/functional/p2p-segwit.py b/test/functional/p2p-segwit.py index 5776d99f6e..a240d79013 100755 --- a/test/functional/p2p-segwit.py +++ b/test/functional/p2p-segwit.py @@ -59,7 +59,7 @@ def test_witness_block(rpc, p2p, block, accepted, with_witness=True): p2p.sync_with_ping() assert_equal(rpc.getbestblockhash() == block.hash, accepted) -class TestNode(NodeConnCB): +class TestNode(P2PInterface): def __init__(self): super().__init__() self.getdataset = set() diff --git a/test/functional/p2p-timeouts.py b/test/functional/p2p-timeouts.py index 21ae29eb6a..b2f3a861cf 100755 --- a/test/functional/p2p-timeouts.py +++ b/test/functional/p2p-timeouts.py @@ -27,7 +27,7 @@ from test_framework.mininode import * from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * -class TestNode(NodeConnCB): +class TestNode(P2PInterface): def on_version(self, message): # Don't send a verack in response pass diff --git a/test/functional/p2p-versionbits-warning.py b/test/functional/p2p-versionbits-warning.py index a6265f6d9c..be137381d0 100755 --- a/test/functional/p2p-versionbits-warning.py +++ b/test/functional/p2p-versionbits-warning.py @@ -23,7 +23,7 @@ WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible un WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})".format(VB_UNKNOWN_BIT) VB_PATTERN = re.compile("^Warning.*versionbit") -class TestNode(NodeConnCB): +class TestNode(P2PInterface): def on_inv(self, message): pass diff --git a/test/functional/sendheaders.py b/test/functional/sendheaders.py index b589d0e8a5..99b7f6b99e 100755 --- a/test/functional/sendheaders.py +++ b/test/functional/sendheaders.py @@ -91,7 +91,7 @@ from test_framework.mininode import ( CInv, NODE_WITNESS, NetworkThread, - NodeConnCB, + P2PInterface, mininode_lock, msg_block, msg_getblocks, @@ -110,7 +110,7 @@ from test_framework.util import ( DIRECT_FETCH_RESPONSE_TIME = 0.05 -class BaseNode(NodeConnCB): +class BaseNode(P2PInterface): def __init__(self): super().__init__() diff --git a/test/functional/test_framework/comptool.py b/test/functional/test_framework/comptool.py index 2f64fba753..f0f5c847ca 100755 --- a/test/functional/test_framework/comptool.py +++ b/test/functional/test_framework/comptool.py @@ -39,7 +39,7 @@ class RejectResult(): def __repr__(self): return '%i:%s' % (self.code,self.reason or '*') -class TestNode(NodeConnCB): +class TestNode(P2PInterface): def __init__(self, block_store, tx_store): super().__init__() diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py index c580d99c79..9e92a70da1 100755 --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -9,10 +9,8 @@ This python code was modified from ArtForz' public domain half-a-node, as found in the mini-node branch of http://github.com/jgarzik/pynode. -NodeConn: an object which manages p2p connectivity to a bitcoin node -NodeConnCB: a base class that describes the interface for receiving - callbacks with network messages from a NodeConn -""" +P2PConnection: A low-level connection object to a node's P2P interface +P2PInterface: A high-level interface object for communicating to a node over P2P""" import asyncore from collections import defaultdict from io import BytesIO @@ -57,7 +55,7 @@ MAGIC_BYTES = { "regtest": b"\xfa\xbf\xb5\xda", # regtest } -class NodeConn(asyncore.dispatcher): +class P2PConnection(asyncore.dispatcher): """A low-level connection object to a node's P2P interface. This class is responsible for: @@ -68,9 +66,7 @@ class NodeConn(asyncore.dispatcher): - logging messages as they are sent and received This class contains no logic for handing the P2P message payloads. It must be - sub-classed and the on_message() callback overridden. - - TODO: rename this class P2PConnection.""" + sub-classed and the on_message() callback overridden.""" def __init__(self): super().__init__(map=mininode_socket_map) @@ -244,7 +240,7 @@ class NodeConn(asyncore.dispatcher): logger.debug(log_message) -class NodeConnCB(NodeConn): +class P2PInterface(P2PConnection): """A high-level P2P interface class for communicating with a Bitcoin node. This class provides high-level callbacks for processing P2P message @@ -252,9 +248,7 @@ class NodeConnCB(NodeConn): node over P2P. Individual testcases should subclass this and override the on_* methods - if they want to alter message handling behaviour. - - TODO: rename this class P2PInterface""" + if they want to alter message handling behaviour.""" def __init__(self): super().__init__() @@ -399,10 +393,10 @@ mininode_socket_map = dict() # One lock for synchronizing all data access between the networking thread (see # NetworkThread below) and the thread running the test logic. For simplicity, -# NodeConn acquires this lock whenever delivering a message to a NodeConnCB, +# P2PConnection acquires this lock whenever delivering a message to a P2PInterface, # and whenever adding anything to the send buffer (in send_message()). This # lock should be acquired in the thread running the test logic to synchronize -# access to any data shared with the NodeConnCB or NodeConn. +# access to any data shared with the P2PInterface or P2PConnection. mininode_lock = RLock() class NetworkThread(Thread): diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index 4590b4c650..54fe689686 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -4,7 +4,6 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Base class for RPC testing.""" -from collections import deque from enum import Enum import logging import optparse @@ -149,32 +148,19 @@ class BitcoinTestFramework(): shutil.rmtree(self.options.tmpdir) else: self.log.warning("Not cleaning up dir %s" % self.options.tmpdir) - if os.getenv("PYTHON_DEBUG", ""): - # Dump the end of the debug logs, to aid in debugging rare - # travis failures. - import glob - filenames = [self.options.tmpdir + "/test_framework.log"] - filenames += glob.glob(self.options.tmpdir + "/node*/regtest/debug.log") - MAX_LINES_TO_PRINT = 1000 - for fn in filenames: - try: - with open(fn, 'r') as f: - print("From", fn, ":") - print("".join(deque(f, MAX_LINES_TO_PRINT))) - except OSError: - print("Opening file %s failed." % fn) - traceback.print_exc() if success == TestStatus.PASSED: self.log.info("Tests successful") - sys.exit(TEST_EXIT_PASSED) + exit_code = TEST_EXIT_PASSED elif success == TestStatus.SKIPPED: self.log.info("Test skipped") - sys.exit(TEST_EXIT_SKIPPED) + exit_code = TEST_EXIT_SKIPPED else: self.log.error("Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir) - logging.shutdown() - sys.exit(TEST_EXIT_FAILED) + self.log.error("Hint: Call {} '{}' to consolidate all logs".format(os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + "/../combine_logs.py"), self.options.tmpdir)) + exit_code = TEST_EXIT_FAILED + logging.shutdown() + sys.exit(exit_code) # Methods to override in subclass test scripts. def set_test_params(self): diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 2202d65b5e..e38146a79a 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -15,6 +15,7 @@ For a description of arguments recognized by test scripts, see """ import argparse +from collections import deque import configparser import datetime import os @@ -175,6 +176,7 @@ def main(): epilog=''' Help text and arguments for individual test script:''', formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('--combinedlogslen', '-c', type=int, default=0, help='print a combined log (of length n lines) from all test nodes and test framework to the console on failure.') parser.add_argument('--coverage', action='store_true', help='generate a basic coverage report for the RPC interface') parser.add_argument('--exclude', '-x', help='specify a comma-separated-list of scripts to exclude.') parser.add_argument('--extended', action='store_true', help='run the extended test suite in addition to the basic tests') @@ -267,9 +269,9 @@ def main(): if not args.keepcache: shutil.rmtree("%s/test/cache" % config["environment"]["BUILDDIR"], ignore_errors=True) - run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], tmpdir, args.jobs, args.coverage, passon_args) + run_tests(test_list, config["environment"]["SRCDIR"], config["environment"]["BUILDDIR"], config["environment"]["EXEEXT"], tmpdir, args.jobs, args.coverage, passon_args, args.combinedlogslen) -def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_coverage=False, args=[]): +def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_coverage=False, args=[], combined_logs_len=0): # Warn if bitcoind is already running (unix only) try: if subprocess.check_output(["pidof", "bitcoind"]) is not None: @@ -315,7 +317,7 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove max_len_name = len(max(test_list, key=len)) for _ in range(len(test_list)): - test_result, stdout, stderr = job_queue.get_next() + test_result, testdir, stdout, stderr = job_queue.get_next() test_results.append(test_result) if test_result.status == "Passed": @@ -326,6 +328,14 @@ def run_tests(test_list, src_dir, build_dir, exeext, tmpdir, jobs=1, enable_cove print("\n%s%s%s failed, Duration: %s s\n" % (BOLD[1], test_result.name, BOLD[0], test_result.time)) print(BOLD[1] + 'stdout:\n' + BOLD[0] + stdout + '\n') print(BOLD[1] + 'stderr:\n' + BOLD[0] + stderr + '\n') + if combined_logs_len and os.path.isdir(testdir): + # Print the final `combinedlogslen` lines of the combined logs + print('{}Combine the logs and print the last {} lines ...{}'.format(BOLD[1], combined_logs_len, BOLD[0])) + print('\n============') + print('{}Combined log for {}:{}'.format(BOLD[1], testdir, BOLD[0])) + print('============\n') + combined_logs, _ = subprocess.Popen([os.path.join(tests_dir, 'combine_logs.py'), '-c', testdir], universal_newlines=True, stdout=subprocess.PIPE).communicate() + print("\n".join(deque(combined_logs.splitlines(), combined_logs_len))) print_results(test_results, max_len_name, (int(time.time() - time0))) @@ -390,13 +400,15 @@ class TestHandler: log_stdout = tempfile.SpooledTemporaryFile(max_size=2**16) log_stderr = tempfile.SpooledTemporaryFile(max_size=2**16) test_argv = t.split() - tmpdir = ["--tmpdir=%s/%s_%s" % (self.tmpdir, re.sub(".py$", "", test_argv[0]), portseed)] + testdir = "{}/{}_{}".format(self.tmpdir, re.sub(".py$", "", test_argv[0]), portseed) + tmpdir_arg = ["--tmpdir={}".format(testdir)] self.jobs.append((t, time.time(), - subprocess.Popen([self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + portseed_arg + tmpdir, + subprocess.Popen([self.tests_dir + test_argv[0]] + test_argv[1:] + self.flags + portseed_arg + tmpdir_arg, universal_newlines=True, stdout=log_stdout, stderr=log_stderr), + testdir, log_stdout, log_stderr)) if not self.jobs: @@ -405,7 +417,7 @@ class TestHandler: # Return first proc that finishes time.sleep(.5) for j in self.jobs: - (name, time0, proc, log_out, log_err) = j + (name, time0, proc, testdir, log_out, log_err) = j if os.getenv('TRAVIS') == 'true' and int(time.time() - time0) > 20 * 60: # In travis, timeout individual tests after 20 minutes (to stop tests hanging and not # providing useful output. @@ -423,7 +435,7 @@ class TestHandler: self.num_running -= 1 self.jobs.remove(j) - return TestResult(name, status, int(time.time() - time0)), stdout, stderr + return TestResult(name, status, int(time.time() - time0)), testdir, stdout, stderr print('.', end='', flush=True) class TestResult(): |