From 2097c66585f49d3f0a175b1b13493b6199d992b9 Mon Sep 17 00:00:00 2001 From: PastaClaw Date: Mon, 14 Sep 2026 22:22:03 -0500 Subject: [PATCH 1/2] Merge bitcoin/bitcoin#27895: test: clean up is node stopped 6779e6ed7f9ad455566dca8c5aa4ef13b6715cd5 test: clean up is node stopped (dimitaracev) Pull request description: Fixes #27893 Use f'strings for the message when asserting `expected_ret_code` and `return_code`. Change the `expected_ret_code` from an optional to have a default value of `0`. cc MarcoFalke ACKs for top commit: MarcoFalke: lgtm ACK 6779e6ed7f9ad455566dca8c5aa4ef13b6715cd5 stickies-v: ACK 6779e6ed7f9ad455566dca8c5aa4ef13b6715cd5 brunoerg: ACK 6779e6ed7f9ad455566dca8c5aa4ef13b6715cd5 Tree-SHA512: af84e7ffe467ced29236dee9206687786a2efb89ab8b039c3ebfb93ea23fc273206cd51f20c9fb6bee4135770e9a649538942571d9c0be83ba9535fa8e59cb28 --- test/functional/test_framework/test_node.py | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index bc3ea083a38e..1e1fcddcc43c 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -430,7 +430,7 @@ def stop_node(self, expected_stderr='', *, wait=0, wait_until_stopped=True): if wait_until_stopped: self.wait_until_stopped() - def is_node_stopped(self, expected_ret_code=None): + def is_node_stopped(self, expected_ret_code=0): """Checks whether the node has stopped. Returns True if the node has stopped. False otherwise. @@ -442,13 +442,8 @@ def is_node_stopped(self, expected_ret_code=None): return False # process has stopped. Assert that it didn't return an error code. - # unless 'expected_ret_code' is provided. - if expected_ret_code is not None: - assert return_code == expected_ret_code, self._node_msg( - "Node returned unexpected exit code (%d) vs (%d) when stopping" % (return_code, expected_ret_code)) - else: - assert return_code == 0, self._node_msg( - "Node returned non-zero exit code (%d) when stopping" % return_code) + assert return_code == expected_ret_code, self._node_msg( + f"Node returned unexpected exit code ({return_code}) vs ({expected_ret_code}) when stopping") self.running = False self.process = None self.rpc_connected = False @@ -457,7 +452,7 @@ def is_node_stopped(self, expected_ret_code=None): return True def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT, expect_error=False): - expected_ret_code = 1 if expect_error else None # Whether node shutdown return EXIT_FAILURE or EXIT_SUCCESS + expected_ret_code = 1 if expect_error else 0 # Whether node shutdown return EXIT_FAILURE or EXIT_SUCCESS wait_until_helper(lambda: self.is_node_stopped(expected_ret_code=expected_ret_code), timeout=timeout, timeout_factor=self.timeout_factor) def replace_in_config(self, replacements): From 94d1b3bfc80ab45db1d0f688755952cfe8afe03a Mon Sep 17 00:00:00 2001 From: PastaClaw Date: Tue, 15 Sep 2026 00:15:25 -0500 Subject: [PATCH 2/2] Merge bitcoin/bitcoin#28028: test: Check expected_stderr after stop faf902858d38150caa8991b0ab9d7cfee2905684 test: Check expected_stderr after stop (MarcoFalke) Pull request description: This fixes a bug where stderr wasn't checked for the shutdown sequence. Fix that by waiting for the shutdown to finish and then check stderr. ACKs for top commit: theStack: ACK faf902858d38150caa8991b0ab9d7cfee2905684 Tree-SHA512: a70cd1e6cda84d542782e41e8b59741dbcd472c0d0575bcef5cbfd1418473ce94efe921481d557bae3fbbdd78f1c49c09c48872883c052d87c5c9a9a51492692 --- test/functional/feature_abortnode.py | 2 +- test/functional/test_framework/test_node.py | 27 +++++++++++---------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/test/functional/feature_abortnode.py b/test/functional/feature_abortnode.py index b843176015f6..81467c8af034 100755 --- a/test/functional/feature_abortnode.py +++ b/test/functional/feature_abortnode.py @@ -40,7 +40,7 @@ def run_test(self): # Check that node0 aborted self.log.info("Waiting for crash") - self.nodes[0].wait_until_stopped(timeout=5, expect_error=True) + self.nodes[0].wait_until_stopped(timeout=5, expect_error=True, expected_stderr="Error: A fatal internal error occurred, see debug.log for details") self.log.info("Node crashed - now verifying restart fails") self.nodes[0].assert_start_raises_init_error() diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py index 1e1fcddcc43c..2adb223cd2b2 100755 --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -416,21 +416,13 @@ def stop_node(self, expected_stderr='', *, wait=0, wait_until_stopped=True): for profile_name in tuple(self.perf_subprocesses.keys()): self._stop_perf(profile_name) - # Check that stderr is as expected - self.stderr.seek(0) - stderr = self.stderr.read().decode('utf-8').strip() - if stderr != expected_stderr: - raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr)) - - self.stdout.close() - self.stderr.close() - del self.p2ps[:] + assert (not expected_stderr) or wait_until_stopped # Must wait to check stderr if wait_until_stopped: - self.wait_until_stopped() + self.wait_until_stopped(expected_stderr=expected_stderr) - def is_node_stopped(self, expected_ret_code=0): + def is_node_stopped(self, *, expected_stderr="", expected_ret_code=0): """Checks whether the node has stopped. Returns True if the node has stopped. False otherwise. @@ -444,6 +436,15 @@ def is_node_stopped(self, expected_ret_code=0): # process has stopped. Assert that it didn't return an error code. assert return_code == expected_ret_code, self._node_msg( f"Node returned unexpected exit code ({return_code}) vs ({expected_ret_code}) when stopping") + # Check that stderr is as expected + self.stderr.seek(0) + stderr = self.stderr.read().decode('utf-8').strip() + if stderr != expected_stderr: + raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr)) + + self.stdout.close() + self.stderr.close() + self.running = False self.process = None self.rpc_connected = False @@ -451,9 +452,9 @@ def is_node_stopped(self, expected_ret_code=0): self.log.debug("Node stopped") return True - def wait_until_stopped(self, timeout=BITCOIND_PROC_WAIT_TIMEOUT, expect_error=False): + def wait_until_stopped(self, *, timeout=BITCOIND_PROC_WAIT_TIMEOUT, expect_error=False, **kwargs): expected_ret_code = 1 if expect_error else 0 # Whether node shutdown return EXIT_FAILURE or EXIT_SUCCESS - wait_until_helper(lambda: self.is_node_stopped(expected_ret_code=expected_ret_code), timeout=timeout, timeout_factor=self.timeout_factor) + wait_until_helper(lambda: self.is_node_stopped(expected_ret_code=expected_ret_code, **kwargs), timeout=timeout, timeout_factor=self.timeout_factor) def replace_in_config(self, replacements): """