Skip to content

Commit 8f137e6

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#24192: test: Fix feature_init intermittent issues
fa7b075 test: Fix feature_init intermittent issues (MarcoFalke) fa4595d test: Remove random line number feature from feature_init.py (MarcoFalke) Pull request description: The test doesn't work currently because the log might be finalized before `wait_for_debug_log` is started, in which case it will assume the log is empty and fail to detect any line. Fix this by calling `wait_for_debug_log` first. Fixes #24060. Also, remove the "random line number" part of the test, because it doesn't really test anything novel. `wait_for_debug_log` is inherently racy, so will randomly terminate at the exact point or later. So the randomization is already sufficiently covered. ACKs for top commit: jamesob: ACK bitcoin/bitcoin@fa7b075 mzumsande: Code Review ACK fa7b075 Tree-SHA512: f107a04926270a1d9ac8f53b6e5254566d1827ba7d27fd74f9ce909319f8794f8bd46da9c42256bf41b6df26c0bad8b9a0d54e4e148695189af09f31e3948330
2 parents 0ff1391 + fa7b075 commit 8f137e6

File tree

2 files changed

+8
-42
lines changed

2 files changed

+8
-42
lines changed

test/functional/feature_init.py

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Stress tests related to node initialization."""
6-
import random
7-
import time
86
import os
97
from pathlib import Path
108

@@ -26,7 +24,6 @@ def set_test_params(self):
2624
def run_test(self):
2725
"""
2826
- test terminating initialization after seeing a certain log line.
29-
- test terminating init after seeing a random number of log lines.
3027
- test removing certain essential files to test startup error paths.
3128
"""
3229
# TODO: skip Windows for now since it isn't clear how to SIGTERM.
@@ -76,46 +73,14 @@ def check_clean_start():
7673

7774
for terminate_line in lines_to_terminate_after:
7875
self.log.info(f"Starting node and will exit after line '{terminate_line}'")
79-
node.start(extra_args=['-txindex=1'])
80-
81-
num_total_logs = node.wait_for_debug_log([terminate_line], ignore_case=True)
82-
self.log.debug(f"Terminating node after {num_total_logs} log lines seen")
76+
with node.wait_for_debug_log([terminate_line], ignore_case=True):
77+
node.start(extra_args=['-txindex=1'])
78+
self.log.debug("Terminating node after terminate line was found")
8379
sigterm_node()
8480

8581
check_clean_start()
8682
self.stop_node(0)
8783

88-
self.log.info(
89-
f"Terminate at some random point in the init process (max logs: {num_total_logs})")
90-
91-
for _ in range(40):
92-
num_logs = len(Path(node.debug_log_path).read_text().splitlines())
93-
additional_lines = random.randint(1, num_total_logs)
94-
self.log.debug(f"Starting node and will exit after {additional_lines} lines")
95-
node.start(extra_args=['-txindex=1'])
96-
logfile = open(node.debug_log_path, 'rb')
97-
98-
MAX_SECS_TO_WAIT = 10
99-
start = time.time()
100-
num_lines = 0
101-
102-
while True:
103-
line = logfile.readline()
104-
if line:
105-
num_lines += 1
106-
107-
if num_lines >= (num_logs + additional_lines) or \
108-
(time.time() - start) > MAX_SECS_TO_WAIT:
109-
self.log.debug(f"Terminating node after {num_lines} log lines seen")
110-
sigterm_node()
111-
break
112-
113-
if node.process.poll() is not None:
114-
raise AssertionError("node failed to start")
115-
116-
check_clean_start()
117-
self.stop_node(0)
118-
11984
self.log.info("Test startup errors after removing certain essential files")
12085

12186
files_to_disturb = {

test/functional/test_framework/test_node.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,8 @@ def assert_debug_log(self, expected_msgs, unexpected_msgs=None, timeout=2):
422422
time.sleep(0.05)
423423
self._raise_assertion_error('Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(str(expected_msgs), print_log))
424424

425-
def wait_for_debug_log(self, expected_msgs, timeout=10, ignore_case=False) -> int:
425+
@contextlib.contextmanager
426+
def wait_for_debug_log(self, expected_msgs, timeout=60, ignore_case=False):
426427
"""
427428
Block until we see a particular debug log message fragment or until we exceed the timeout.
428429
Return:
@@ -432,6 +433,8 @@ def wait_for_debug_log(self, expected_msgs, timeout=10, ignore_case=False) -> in
432433
prev_size = self.debug_log_bytes()
433434
re_flags = re.MULTILINE | (re.IGNORECASE if ignore_case else 0)
434435

436+
yield
437+
435438
while True:
436439
found = True
437440
with open(self.debug_log_path, encoding='utf-8') as dl:
@@ -443,8 +446,7 @@ def wait_for_debug_log(self, expected_msgs, timeout=10, ignore_case=False) -> in
443446
found = False
444447

445448
if found:
446-
num_logs = len(log.splitlines())
447-
return num_logs
449+
return
448450

449451
if time.time() >= time_end:
450452
print_log = " - " + "\n - ".join(log.splitlines())
@@ -456,7 +458,6 @@ def wait_for_debug_log(self, expected_msgs, timeout=10, ignore_case=False) -> in
456458
self._raise_assertion_error(
457459
'Expected messages "{}" does not partially match log:\n\n{}\n\n'.format(
458460
str(expected_msgs), print_log))
459-
return -1 # useless return to satisfy linter
460461

461462
@contextlib.contextmanager
462463
def profile_with_perf(self, profile_name: str):

0 commit comments

Comments
 (0)