test: Add capability to disable RPC timeout in functional tests.

Modifies the existing --factor flag to --timeout-factor to better express intent.
Adds rules to disable timeout if --timeout-factor is set to 0.
Modfies --timeout-factor help doc to inform users about this feature.
This commit is contained in:
codeShark149
2020-05-18 09:45:55 +05:30
parent dc5333d31f
commit 784ae09625
4 changed files with 18 additions and 16 deletions

View File

@@ -122,9 +122,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, factor): def peer_connect(self, dstaddr, dstport, *, net, timeout_factor):
assert not self.is_connected assert not self.is_connected
self.factor = factor self.timeout_factor = timeout_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:
@@ -372,7 +372,7 @@ class P2PInterface(P2PConnection):
# Connection helper methods # Connection helper methods
def wait_until(self, test_function, timeout): def wait_until(self, test_function, timeout):
wait_until(test_function, timeout=timeout, lock=mininode_lock, factor=self.factor) wait_until(test_function, timeout=timeout, lock=mininode_lock, timeout_factor=self.timeout_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

View File

@@ -102,7 +102,9 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
self.bind_to_localhost_only = True self.bind_to_localhost_only = True
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 if self.options.timeout_factor == 0 :
self.options.timeout_factor = 99999
self.rpc_timeout = int(self.rpc_timeout * self.options.timeout_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."""
@@ -169,7 +171,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
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("--descriptors", default=False, action="store_true", parser.add_argument("--descriptors", default=False, action="store_true",
help="Run test using a descriptor wallet") help="Run test using a descriptor wallet")
parser.add_argument('--factor', type=float, default=1.0, help='adjust test timeouts by a factor') parser.add_argument('--timeout-factor', dest="timeout_factor", type=float, default=1.0, help='adjust test timeouts by a factor. Setting it to 0 disables all timeouts')
self.add_options(parser) self.add_options(parser)
self.options = parser.parse_args() self.options = parser.parse_args()
@@ -445,7 +447,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, timeout_factor=self.options.timeout_factor,
bitcoind=binary[i], bitcoind=binary[i],
bitcoin_cli=binary_cli[i], bitcoin_cli=binary_cli[i],
version=versions[i], version=versions[i],
@@ -592,7 +594,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
extra_args=['-disablewallet'], extra_args=['-disablewallet'],
rpchost=None, rpchost=None,
timewait=self.rpc_timeout, timewait=self.rpc_timeout,
factor=self.options.factor, timeout_factor=self.options.timeout_factor,
bitcoind=self.options.bitcoind, bitcoind=self.options.bitcoind,
bitcoin_cli=self.options.bitcoincli, bitcoin_cli=self.options.bitcoincli,
coverage_dir=None, coverage_dir=None,

View File

@@ -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, *, chain, rpchost, timewait, factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=False): def __init__(self, i, datadir, *, chain, rpchost, timewait, timeout_factor, bitcoind, bitcoin_cli, coverage_dir, cwd, extra_conf=None, extra_args=None, use_cli=False, start_perf=False, use_valgrind=False, version=None, descriptors=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
@@ -128,7 +128,7 @@ class TestNode():
self.perf_subprocesses = {} self.perf_subprocesses = {}
self.p2ps = [] self.p2ps = []
self.factor = factor self.timeout_factor = timeout_factor
AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key']) AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
PRIV_KEYS = [ PRIV_KEYS = [
@@ -241,7 +241,7 @@ class TestNode():
# The wait is done here to make tests as robust as possible # The wait is done here to make tests as robust as possible
# and prevent racy tests and intermittent failures as much # and prevent racy tests and intermittent failures as much
# as possible. Some tests might not need this, but the # as possible. Some tests might not need this, but the
# overhead is trivial, and the added gurantees are worth # overhead is trivial, and the added guarantees are worth
# the minimal performance cost. # the minimal performance cost.
self.log.debug("RPC successfully started") self.log.debug("RPC successfully started")
if self.use_cli: if self.use_cli:
@@ -349,13 +349,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, factor=self.factor) wait_until(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_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 * self.factor time_end = time.time() + timeout * self.timeout_factor
debug_log = os.path.join(self.datadir, self.chain, 'debug.log') debug_log = os.path.join(self.datadir, self.chain, 'debug.log')
with open(debug_log, encoding='utf-8') as dl: with open(debug_log, encoding='utf-8') as dl:
dl.seek(0, 2) dl.seek(0, 2)
@@ -512,7 +512,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, factor=self.factor)() p2p_conn.peer_connect(**kwargs, net=self.chain, timeout_factor=self.timeout_factor)()
self.p2ps.append(p2p_conn) self.p2ps.append(p2p_conn)
if wait_for_verack: if wait_for_verack:
# Wait for the node to send us the version and verack # Wait for the node to send us the version and verack
@@ -526,7 +526,7 @@ class TestNode():
# transaction that will be added to the mempool as soon as we return here. # transaction that will be added to the mempool as soon as we return here.
# #
# So syncing here is redundant when we only want to send a message, but the cost is low (a few milliseconds) # So syncing here is redundant when we only want to send a message, but the cost is low (a few milliseconds)
# in comparision to the upside of making tests less fragile and unexpected intermittent errors less likely. # in comparison to the upside of making tests less fragile and unexpected intermittent errors less likely.
p2p_conn.sync_with_ping() p2p_conn.sync_with_ping()
return p2p_conn return p2p_conn

View File

@@ -208,10 +208,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'), lock=None, factor=1.0): def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, timeout_factor=1.0):
if attempts == float('inf') and timeout == float('inf'): if attempts == float('inf') and timeout == float('inf'):
timeout = 60 timeout = 60
timeout = timeout * factor timeout = timeout * timeout_factor
attempt = 0 attempt = 0
time_end = time.time() + timeout time_end = time.time() + timeout