diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py --- a/test/functional/test_framework/mininode.py +++ b/test/functional/test_framework/mininode.py @@ -132,8 +132,9 @@ def is_connected(self): return self._transport is not None - def peer_connect(self, dstaddr, dstport, *, net): + def peer_connect(self, dstaddr, dstport, *, net, factor): assert not self.is_connected + self.factor = factor self.dstaddr = dstaddr self.dstport = dstport # The initial message to send after the connection was made: @@ -448,9 +449,13 @@ # Connection helper methods + def wait_until(self, test_function, timeout): + wait_until(test_function, timeout=timeout, + lock=mininode_lock, factor=self.factor) + def wait_for_disconnect(self, timeout=60): def test_function(): return not self.is_connected - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) # Message receiving helper methods @@ -461,7 +466,7 @@ return False return self.last_message['tx'].tx.rehash() == txid - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_block(self, blockhash, timeout=60): def test_function(): @@ -469,7 +474,7 @@ return self.last_message.get( "block") and self.last_message["block"].block.rehash() == blockhash - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_header(self, blockhash, timeout=60): def test_function(): @@ -479,7 +484,7 @@ return False return last_headers.headers[0].rehash() == int(blockhash, 16) - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_merkleblock(self, blockhash, timeout=60): def test_function(): @@ -489,7 +494,7 @@ return False return last_filtered_block.merkleblock.header.rehash() == int(blockhash, 16) - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_getdata(self, hash_list, timeout=60): """Waits for a getdata message. @@ -503,7 +508,7 @@ return False return [x.hash for x in last_data.inv] == hash_list - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_getheaders(self, timeout=60): """Waits for a getheaders message. @@ -517,7 +522,7 @@ assert self.is_connected return self.last_message.get("getheaders") - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_inv(self, expected_inv, timeout=60): """Waits for an INV message and checks that the first inv object in the message was as expected.""" @@ -531,13 +536,13 @@ self.last_message["inv"].inv[0].type == expected_inv[0].type and \ self.last_message["inv"].inv[0].hash == expected_inv[0].hash - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) def wait_for_verack(self, timeout=60): def test_function(): return self.message_count["verack"] - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) # Message sending helper functions @@ -554,7 +559,7 @@ return self.last_message.get( "pong") and self.last_message["pong"].nonce == self.ping_counter - wait_until(test_function, timeout=timeout, lock=mininode_lock) + self.wait_until(test_function, timeout=timeout) self.ping_counter += 1 @@ -679,8 +684,8 @@ else: self.send_message( msg_headers([CBlockHeader(block) for block in blocks])) - wait_until( - lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock) + self.wait_until( + lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout) if expect_disconnect: self.wait_for_disconnect(timeout=timeout) @@ -688,8 +693,8 @@ self.sync_with_ping(timeout=timeout) if success: - wait_until(lambda: node.getbestblockhash() == - blocks[-1].hash, timeout=timeout) + self.wait_until(lambda: node.getbestblockhash() == + blocks[-1].hash, timeout=timeout) else: assert node.getbestblockhash() != blocks[-1].hash diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -109,6 +109,8 @@ # know the parser options during setup. self.parse_args() self.set_test_params() + # optionally, increase timeout by a factor + self.rpc_timeout = int(self.rpc_timeout * self.options.factor) def main(self): """Main function. This should not be overridden by the subclass test scripts.""" @@ -172,6 +174,11 @@ help="set a random seed for deterministically reproducing a previous test run") parser.add_argument("--with-axionactivation", dest="axionactivation", default=False, action="store_true", help="Activate axion update on timestamp {}".format(TIMESTAMP_IN_THE_PAST)) + parser.add_argument( + '--factor', + type=float, + default=1.0, + help='adjust test timeouts by a factor') self.add_options(parser) self.options = parser.parse_args() @@ -412,6 +419,7 @@ rpc_port=rpc_port(i), p2p_port=p2p_port(i), timewait=self.rpc_timeout, + factor=self.options.factor, bitcoind=binary[i], bitcoin_cli=self.options.bitcoincli, coverage_dir=self.options.coveragedir, @@ -574,6 +582,7 @@ rpc_port=rpc_port(CACHE_NODE_ID), p2p_port=p2p_port(CACHE_NODE_ID), timewait=self.rpc_timeout, + factor=self.options.factor, bitcoind=self.options.bitcoind, bitcoin_cli=self.options.bitcoincli, coverage_dir=None, diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -61,7 +61,7 @@ To make things easier for the test writer, any unrecognised messages will be dispatched to the RPC connection.""" - def __init__(self, i, datadir, *, chain, host, rpc_port, p2p_port, timewait, bitcoind, bitcoin_cli, + def __init__(self, i, datadir, *, chain, host, rpc_port, p2p_port, timewait, factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, emulator=None, start_perf=False, use_valgrind=False): """ Kwargs: @@ -146,6 +146,7 @@ # Cache perf subprocesses here by their data output filename. self.perf_subprocesses = {} self.p2ps = [] + self.factor = factor AddressKeyPair = collections.namedtuple( 'AddressKeyPair', ['address', 'key']) @@ -419,7 +420,7 @@ return True def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT): - wait_until(self.is_node_stopped, timeout=timeout) + wait_until(self.is_node_stopped, timeout=timeout, factor=self.factor) @contextlib.contextmanager def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2): @@ -437,7 +438,7 @@ raise AssertionError("Expected debug messages is empty") if unexpected_msgs is None: unexpected_msgs = [] - time_end = time.time() + timeout + time_end = time.time() + timeout * self.factor debug_log = os.path.join(self.datadir, self.chain, 'debug.log') with open(debug_log, encoding='utf-8') as dl: dl.seek(0, 2) @@ -634,7 +635,7 @@ if 'dstaddr' not in kwargs: kwargs['dstaddr'] = '127.0.0.1' - p2p_conn.peer_connect(**kwargs, net=self.chain)() + p2p_conn.peer_connect(**kwargs, net=self.chain, factor=self.factor)() self.p2ps.append(p2p_conn) if wait_for_verack: # Wait for the node to send us the version and verack diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -248,9 +248,10 @@ def wait_until(predicate, *, attempts=float('inf'), - timeout=float('inf'), lock=None): + timeout=float('inf'), lock=None, factor=1.0): if attempts == float('inf') and timeout == float('inf'): timeout = 60 + timeout = timeout * factor attempt = 0 time_end = time.time() + timeout @@ -310,7 +311,7 @@ """ proxy_kwargs = {} if timeout is not None: - proxy_kwargs['timeout'] = timeout + proxy_kwargs['timeout'] = int(timeout) proxy = AuthServiceProxy(url, **proxy_kwargs) proxy.url = url # store URL on proxy for info