Skip to content

Commit 362f9c6

Browse files
author
MarcoFalke
committed
Merge #18986: tests: Add capability to disable RPC timeout in functional tests
38c3dd9 docs: Add notes on how to diasble rpc timeout in functional tests while attatching gdb. (codeShark149) 784ae09 test: Add capability to disable RPC timeout in functional tests. (codeShark149) Pull request description: Many times, especially while debugging RPC callbacks to core using gdb, the test timeout kicks in before the response can get back. This can be annoying and requires restarting the functional test as well as gdb attachment. This PR adds a `--notimeout` flag into `test_framework` and sets the `rpc_timeout` accordingly if the flag is set. The same effect can be achieved with newly added `--factor` flag but keeping a separate flag that explicitly disables the timeout can be easier for new testers to find it out and separates its purpose from the `--factor` flag. Requesting review ryanofsky jnewbery as per the IRC discussion. Update: After initial round of review, the approach is modified to accommodate the functionality in already existing `--factor` flag. `--factor` is changed to `--timeout-factor` to express its intent better. ACKs for top commit: MarcoFalke: ACK 38c3dd9 and thanks for fixing up all my typos 😅 jnewbery: ACK 38c3dd9. Tree-SHA512: 9458dd1010288c62f8bb83f7a4893284fbbf938882dd65fc9e08810a910db07ef676e3100266028e5d4c8ce407b2267b3860595015da070c84a9d4a9816797db
2 parents dc5333d + 38c3dd9 commit 362f9c6

File tree

5 files changed

+22
-16
lines changed

5 files changed

+22
-16
lines changed

test/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,10 @@ gdb /home/example/bitcoind <pid>
225225
Note: gdb attach step may require ptrace_scope to be modified, or `sudo` preceding the `gdb`.
226226
See this link for considerations: https://www.kernel.org/doc/Documentation/security/Yama.txt
227227

228+
Often while debugging rpc calls from functional tests, the test might reach timeout before
229+
process can return a response. Use `--timeout-factor 0` to disable all rpc timeouts for that partcular
230+
functional test. Ex: `test/functional/wallet_hd.py --timeout-factor 0`.
231+
228232
##### Profiling
229233

230234
An easy way to profile node performance during functional tests is provided

test/functional/test_framework/mininode.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,9 @@ def __init__(self):
122122
def is_connected(self):
123123
return self._transport is not None
124124

125-
def peer_connect(self, dstaddr, dstport, *, net, factor):
125+
def peer_connect(self, dstaddr, dstport, *, net, timeout_factor):
126126
assert not self.is_connected
127-
self.factor = factor
127+
self.timeout_factor = timeout_factor
128128
self.dstaddr = dstaddr
129129
self.dstport = dstport
130130
# The initial message to send after the connection was made:
@@ -372,7 +372,7 @@ def on_version(self, message):
372372
# Connection helper methods
373373

374374
def wait_until(self, test_function, timeout):
375-
wait_until(test_function, timeout=timeout, lock=mininode_lock, factor=self.factor)
375+
wait_until(test_function, timeout=timeout, lock=mininode_lock, timeout_factor=self.timeout_factor)
376376

377377
def wait_for_disconnect(self, timeout=60):
378378
test_function = lambda: not self.is_connected

test/functional/test_framework/test_framework.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ def __init__(self):
102102
self.bind_to_localhost_only = True
103103
self.set_test_params()
104104
self.parse_args()
105-
self.rpc_timeout = int(self.rpc_timeout * self.options.factor) # optionally, increase timeout by a factor
105+
if self.options.timeout_factor == 0 :
106+
self.options.timeout_factor = 99999
107+
self.rpc_timeout = int(self.rpc_timeout * self.options.timeout_factor) # optionally, increase timeout by a factor
106108

107109
def main(self):
108110
"""Main function. This should not be overridden by the subclass test scripts."""
@@ -169,7 +171,7 @@ def parse_args(self):
169171
help="set a random seed for deterministically reproducing a previous test run")
170172
parser.add_argument("--descriptors", default=False, action="store_true",
171173
help="Run test using a descriptor wallet")
172-
parser.add_argument('--factor', type=float, default=1.0, help='adjust test timeouts by a factor')
174+
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')
173175
self.add_options(parser)
174176
self.options = parser.parse_args()
175177

@@ -445,7 +447,7 @@ def get_bin_from_version(version, bin_name, bin_default):
445447
chain=self.chain,
446448
rpchost=rpchost,
447449
timewait=self.rpc_timeout,
448-
factor=self.options.factor,
450+
timeout_factor=self.options.timeout_factor,
449451
bitcoind=binary[i],
450452
bitcoin_cli=binary_cli[i],
451453
version=versions[i],
@@ -592,7 +594,7 @@ def _initialize_chain(self):
592594
extra_args=['-disablewallet'],
593595
rpchost=None,
594596
timewait=self.rpc_timeout,
595-
factor=self.options.factor,
597+
timeout_factor=self.options.timeout_factor,
596598
bitcoind=self.options.bitcoind,
597599
bitcoin_cli=self.options.bitcoincli,
598600
coverage_dir=None,

test/functional/test_framework/test_node.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class TestNode():
6262
To make things easier for the test writer, any unrecognised messages will
6363
be dispatched to the RPC connection."""
6464

65-
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):
65+
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):
6666
"""
6767
Kwargs:
6868
start_perf (bool): If True, begin profiling the node with `perf` as soon as
@@ -128,7 +128,7 @@ def __init__(self, i, datadir, *, chain, rpchost, timewait, factor, bitcoind, bi
128128
self.perf_subprocesses = {}
129129

130130
self.p2ps = []
131-
self.factor = factor
131+
self.timeout_factor = timeout_factor
132132

133133
AddressKeyPair = collections.namedtuple('AddressKeyPair', ['address', 'key'])
134134
PRIV_KEYS = [
@@ -241,7 +241,7 @@ def wait_for_rpc_connection(self):
241241
# The wait is done here to make tests as robust as possible
242242
# and prevent racy tests and intermittent failures as much
243243
# as possible. Some tests might not need this, but the
244-
# overhead is trivial, and the added gurantees are worth
244+
# overhead is trivial, and the added guarantees are worth
245245
# the minimal performance cost.
246246
self.log.debug("RPC successfully started")
247247
if self.use_cli:
@@ -349,13 +349,13 @@ def is_node_stopped(self):
349349
return True
350350

351351
def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT):
352-
wait_until(self.is_node_stopped, timeout=timeout, factor=self.factor)
352+
wait_until(self.is_node_stopped, timeout=timeout, timeout_factor=self.timeout_factor)
353353

354354
@contextlib.contextmanager
355355
def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2):
356356
if unexpected_msgs is None:
357357
unexpected_msgs = []
358-
time_end = time.time() + timeout * self.factor
358+
time_end = time.time() + timeout * self.timeout_factor
359359
debug_log = os.path.join(self.datadir, self.chain, 'debug.log')
360360
with open(debug_log, encoding='utf-8') as dl:
361361
dl.seek(0, 2)
@@ -512,7 +512,7 @@ def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs):
512512
if 'dstaddr' not in kwargs:
513513
kwargs['dstaddr'] = '127.0.0.1'
514514

515-
p2p_conn.peer_connect(**kwargs, net=self.chain, factor=self.factor)()
515+
p2p_conn.peer_connect(**kwargs, net=self.chain, timeout_factor=self.timeout_factor)()
516516
self.p2ps.append(p2p_conn)
517517
if wait_for_verack:
518518
# Wait for the node to send us the version and verack
@@ -526,7 +526,7 @@ def add_p2p_connection(self, p2p_conn, *, wait_for_verack=True, **kwargs):
526526
# transaction that will be added to the mempool as soon as we return here.
527527
#
528528
# So syncing here is redundant when we only want to send a message, but the cost is low (a few milliseconds)
529-
# in comparision to the upside of making tests less fragile and unexpected intermittent errors less likely.
529+
# in comparison to the upside of making tests less fragile and unexpected intermittent errors less likely.
530530
p2p_conn.sync_with_ping()
531531

532532
return p2p_conn

test/functional/test_framework/util.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,10 @@ def str_to_b64str(string):
208208
def satoshi_round(amount):
209209
return Decimal(amount).quantize(Decimal('0.00000001'), rounding=ROUND_DOWN)
210210

211-
def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, factor=1.0):
211+
def wait_until(predicate, *, attempts=float('inf'), timeout=float('inf'), lock=None, timeout_factor=1.0):
212212
if attempts == float('inf') and timeout == float('inf'):
213213
timeout = 60
214-
timeout = timeout * factor
214+
timeout = timeout * timeout_factor
215215
attempt = 0
216216
time_end = time.time() + timeout
217217

0 commit comments

Comments
 (0)