mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge #18617: test: add factor option to adjust test timeouts
2742c3428633b6ceaab6714635dc3adb74bf121b test: add factor option to adjust test timeouts (Harris) Pull request description: This PR adds a new option **factor** that can be used to adjust timeouts in various functional tests. Several timeouts and functions from `authproxy`, `mininode`, `test_node` and `util` have been adapted to use this option. The factor-option definition is located in `test_framework.py`. Fixes https://github.com/bitcoin/bitcoin/issues/18266 Also Fixes https://github.com/bitcoin/bitcoin/issues/18834 ACKs for top commit: MarcoFalke: Thanks! ACK 2742c3428633b6ceaab6714635dc3adb74bf121b Tree-SHA512: 6d8421933ba2ac1b7db00b70cf2bc242d9842c48121c11aadc30b0985c4a174c86a127d6402d0cd73b993559d60d4f747872d21f9510cf4806e008349780d3ef
This commit is contained in:
parent
86a11a83a2
commit
6bb3e54578
@ -22,7 +22,6 @@ from io import BytesIO
|
|||||||
import logging
|
import logging
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import time
|
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from test_framework.messages import (
|
from test_framework.messages import (
|
||||||
@ -155,8 +154,9 @@ class P2PConnection(asyncio.Protocol):
|
|||||||
def is_connected(self):
|
def is_connected(self):
|
||||||
return self._transport is not None
|
return self._transport is not None
|
||||||
|
|
||||||
def peer_connect(self, dstaddr, dstport, *, net, uacomment=None):
|
def peer_connect(self, dstaddr, dstport, *, net, factor, uacomment=None):
|
||||||
assert not self.is_connected
|
assert not self.is_connected
|
||||||
|
self.factor = factor
|
||||||
self.dstaddr = dstaddr
|
self.dstaddr = dstaddr
|
||||||
self.dstport = dstport
|
self.dstport = dstport
|
||||||
# The initial message to send after the connection was made:
|
# The initial message to send after the connection was made:
|
||||||
@ -440,11 +440,12 @@ class P2PInterface(P2PConnection):
|
|||||||
|
|
||||||
# Connection helper methods
|
# 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 wait_for_disconnect(self, timeout=60):
|
||||||
test_function = lambda: not self.is_connected
|
test_function = lambda: not self.is_connected
|
||||||
wait_until(test_function, timeout=timeout, lock=mininode_lock)
|
self.wait_until(test_function, timeout=timeout)
|
||||||
# This is a hack. The related issues should be fixed by bitcoin 14119 and 14457.
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# Message receiving helper methods
|
# Message receiving helper methods
|
||||||
|
|
||||||
@ -455,14 +456,14 @@ class P2PInterface(P2PConnection):
|
|||||||
return False
|
return False
|
||||||
return self.last_message['tx'].tx.rehash() == txid
|
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 wait_for_block(self, blockhash, timeout=60):
|
||||||
def test_function():
|
def test_function():
|
||||||
assert self.is_connected
|
assert self.is_connected
|
||||||
return self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
|
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 wait_for_header(self, blockhash, timeout=60):
|
||||||
def test_function():
|
def test_function():
|
||||||
@ -472,7 +473,7 @@ class P2PInterface(P2PConnection):
|
|||||||
return False
|
return False
|
||||||
return last_headers.headers[0].rehash() == blockhash
|
return last_headers.headers[0].rehash() == blockhash
|
||||||
|
|
||||||
wait_until(test_function, timeout=timeout, lock=mininode_lock)
|
self.wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
def wait_for_getdata(self, timeout=60):
|
def wait_for_getdata(self, timeout=60):
|
||||||
"""Waits for a getdata message.
|
"""Waits for a getdata message.
|
||||||
@ -486,7 +487,7 @@ class P2PInterface(P2PConnection):
|
|||||||
assert self.is_connected
|
assert self.is_connected
|
||||||
return self.last_message.get("getdata")
|
return self.last_message.get("getdata")
|
||||||
|
|
||||||
wait_until(test_function, timeout=timeout, lock=mininode_lock)
|
self.wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
def wait_for_getheaders(self, timeout=60):
|
def wait_for_getheaders(self, timeout=60):
|
||||||
"""Waits for a getheaders message.
|
"""Waits for a getheaders message.
|
||||||
@ -501,7 +502,7 @@ class P2PInterface(P2PConnection):
|
|||||||
return self.last_message.get("getheaders2") if self.nServices & NODE_HEADERS_COMPRESSED \
|
return self.last_message.get("getheaders2") if self.nServices & NODE_HEADERS_COMPRESSED \
|
||||||
else self.last_message.get("getheaders")
|
else self.last_message.get("getheaders")
|
||||||
|
|
||||||
wait_until(test_function, timeout=timeout, lock=mininode_lock)
|
self.wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
# TODO: enable when p2p_filter.py is backported
|
# TODO: enable when p2p_filter.py is backported
|
||||||
# def wait_for_inv(self, expected_inv, timeout=60):
|
# def wait_for_inv(self, expected_inv, timeout=60):
|
||||||
@ -515,13 +516,13 @@ class P2PInterface(P2PConnection):
|
|||||||
# self.last_message["inv"].inv[0].type == expected_inv[0].type and \
|
# self.last_message["inv"].inv[0].type == expected_inv[0].type and \
|
||||||
# self.last_message["inv"].inv[0].hash == expected_inv[0].hash
|
# 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 wait_for_verack(self, timeout=60):
|
||||||
def test_function():
|
def test_function():
|
||||||
return "verack" in self.last_message
|
return "verack" in self.last_message
|
||||||
|
|
||||||
wait_until(test_function, timeout=timeout, lock=mininode_lock)
|
self.wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
# Message sending helper functions
|
# Message sending helper functions
|
||||||
|
|
||||||
@ -537,7 +538,7 @@ class P2PInterface(P2PConnection):
|
|||||||
assert self.is_connected
|
assert self.is_connected
|
||||||
return self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter
|
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
|
self.ping_counter += 1
|
||||||
|
|
||||||
|
|
||||||
@ -666,7 +667,7 @@ class P2PDataStore(P2PInterface):
|
|||||||
self.send_message(msg_block(block=b))
|
self.send_message(msg_block(block=b))
|
||||||
else:
|
else:
|
||||||
self.send_message(msg_headers([CBlockHeader(block) for block in blocks]))
|
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:
|
if expect_disconnect:
|
||||||
self.wait_for_disconnect()
|
self.wait_for_disconnect()
|
||||||
@ -674,7 +675,7 @@ class P2PDataStore(P2PInterface):
|
|||||||
self.sync_with_ping()
|
self.sync_with_ping()
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout)
|
self.wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout)
|
||||||
else:
|
else:
|
||||||
assert node.getbestblockhash() != blocks[-1].hash
|
assert node.getbestblockhash() != blocks[-1].hash
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||||||
self.extra_args_from_options = []
|
self.extra_args_from_options = []
|
||||||
self.set_test_params()
|
self.set_test_params()
|
||||||
self.parse_args()
|
self.parse_args()
|
||||||
|
self.rpc_timeout = int(self.rpc_timeout * self.options.factor) # optionally, increase timeout by a factor
|
||||||
|
|
||||||
def main(self):
|
def main(self):
|
||||||
"""Main function. This should not be overridden by the subclass test scripts."""
|
"""Main function. This should not be overridden by the subclass test scripts."""
|
||||||
@ -188,6 +189,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||||||
help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown, valgrind 3.14 or later required")
|
help="run nodes under the valgrind memory error detector: expect at least a ~10x slowdown, valgrind 3.14 or later required")
|
||||||
parser.add_argument("--randomseed", type=int,
|
parser.add_argument("--randomseed", type=int,
|
||||||
help="set a random seed for deterministically reproducing a previous test run")
|
help="set a random seed for deterministically reproducing a previous test run")
|
||||||
|
parser.add_argument('--factor', type=float, default=1.0, help='adjust test timeouts by a factor')
|
||||||
self.add_options(parser)
|
self.add_options(parser)
|
||||||
# Running TestShell in a Jupyter notebook causes an additional -f argument
|
# Running TestShell in a Jupyter notebook causes an additional -f argument
|
||||||
# To keep TestShell from failing with an "unrecognized argument" error, we add a dummy "-f" argument
|
# To keep TestShell from failing with an "unrecognized argument" error, we add a dummy "-f" argument
|
||||||
@ -440,6 +442,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||||||
chain=self.chain,
|
chain=self.chain,
|
||||||
rpchost=rpchost,
|
rpchost=rpchost,
|
||||||
timewait=self.rpc_timeout,
|
timewait=self.rpc_timeout,
|
||||||
|
factor=self.options.factor,
|
||||||
bitcoind=binary[i],
|
bitcoind=binary[i],
|
||||||
bitcoin_cli=self.options.bitcoincli,
|
bitcoin_cli=self.options.bitcoincli,
|
||||||
mocktime=self.mocktime,
|
mocktime=self.mocktime,
|
||||||
@ -613,6 +616,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
|||||||
extra_args_from_options=self.extra_args_from_options,
|
extra_args_from_options=self.extra_args_from_options,
|
||||||
rpchost=None,
|
rpchost=None,
|
||||||
timewait=self.rpc_timeout,
|
timewait=self.rpc_timeout,
|
||||||
|
factor=self.options.factor,
|
||||||
bitcoind=self.options.bitcoind,
|
bitcoind=self.options.bitcoind,
|
||||||
bitcoin_cli=self.options.bitcoincli,
|
bitcoin_cli=self.options.bitcoincli,
|
||||||
mocktime=self.mocktime,
|
mocktime=self.mocktime,
|
||||||
|
@ -62,7 +62,7 @@ class TestNode():
|
|||||||
To make things easier for the test writer, any unrecognised messages will
|
To make things easier for the test writer, any unrecognised messages will
|
||||||
be dispatched to the RPC connection."""
|
be dispatched to the RPC connection."""
|
||||||
|
|
||||||
def __init__(self, i, datadir, extra_args_from_options, *, chain, rpchost, timewait, bitcoind, bitcoin_cli, mocktime, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False):
|
def __init__(self, i, datadir, extra_args_from_options, *, chain, rpchost, timewait, factor, bitcoind, bitcoin_cli, mocktime, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False):
|
||||||
"""
|
"""
|
||||||
Kwargs:
|
Kwargs:
|
||||||
start_perf (bool): If True, begin profiling the node with `perf` as soon as
|
start_perf (bool): If True, begin profiling the node with `perf` as soon as
|
||||||
@ -131,6 +131,7 @@ class TestNode():
|
|||||||
self.perf_subprocesses = {}
|
self.perf_subprocesses = {}
|
||||||
|
|
||||||
self.p2ps = []
|
self.p2ps = []
|
||||||
|
self.factor = factor
|
||||||
|
|
||||||
AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
|
AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
|
||||||
PRIV_KEYS = [
|
PRIV_KEYS = [
|
||||||
@ -337,13 +338,13 @@ class TestNode():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
|
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
|
@contextlib.contextmanager
|
||||||
def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2):
|
def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2):
|
||||||
if unexpected_msgs is None:
|
if unexpected_msgs is None:
|
||||||
unexpected_msgs = []
|
unexpected_msgs = []
|
||||||
time_end = time.time() + timeout
|
time_end = time.time() + timeout * self.factor
|
||||||
chain = get_chain_folder(self.datadir, self.chain)
|
chain = get_chain_folder(self.datadir, self.chain)
|
||||||
debug_log = os.path.join(self.datadir, chain, 'debug.log')
|
debug_log = os.path.join(self.datadir, chain, 'debug.log')
|
||||||
with open(debug_log, encoding='utf-8') as dl:
|
with open(debug_log, encoding='utf-8') as dl:
|
||||||
@ -501,7 +502,7 @@ class TestNode():
|
|||||||
if 'dstaddr' not in kwargs:
|
if 'dstaddr' not in kwargs:
|
||||||
kwargs['dstaddr'] = '127.0.0.1'
|
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)
|
self.p2ps.append(p2p_conn)
|
||||||
if wait_for_verack:
|
if wait_for_verack:
|
||||||
p2p_conn.wait_for_verack()
|
p2p_conn.wait_for_verack()
|
||||||
|
@ -227,9 +227,10 @@ def str_to_b64str(string):
|
|||||||
def satoshi_round(amount):
|
def satoshi_round(amount):
|
||||||
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
|
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
|
||||||
|
|
||||||
def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), sleep=0.05, lock=None, do_assert=True, allow_exception=False):
|
def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), sleep=0.05, factor=1.0, lock=None, do_assert=True, allow_exception=False):
|
||||||
if attempts == float('inf') and timeout == float('inf'):
|
if attempts == float('inf') and timeout == float('inf'):
|
||||||
timeout = 60
|
timeout = 60
|
||||||
|
timeout = timeout * factor
|
||||||
attempt = 0
|
attempt = 0
|
||||||
timeout *= Options.timeout_scale
|
timeout *= Options.timeout_scale
|
||||||
time_end = time.time() + timeout
|
time_end = time.time() + timeout
|
||||||
@ -292,7 +293,7 @@ def get_rpc_proxy(url, node_number, *, timeout=None, coveragedir=None):
|
|||||||
"""
|
"""
|
||||||
proxy_kwargs = {}
|
proxy_kwargs = {}
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
proxy_kwargs['timeout'] = timeout
|
proxy_kwargs['timeout'] = int(timeout)
|
||||||
|
|
||||||
proxy = AuthServiceProxy(url, **proxy_kwargs)
|
proxy = AuthServiceProxy(url, **proxy_kwargs)
|
||||||
proxy.url = url # store URL on proxy for info
|
proxy.url = url # store URL on proxy for info
|
||||||
|
Loading…
Reference in New Issue
Block a user