From bd24bae94eae75b34172056874a50338c9e7c30e Mon Sep 17 00:00:00 2001 From: Hodlinator <172445034+hodlinator@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:15:45 +0100 Subject: [PATCH] qa: Add feature_framework_stop_node.py --- .../functional/feature_framework_stop_node.py | 49 +++++++++++++++++++ test/functional/test_runner.py | 1 + 2 files changed, 50 insertions(+) create mode 100755 test/functional/feature_framework_stop_node.py diff --git a/test/functional/feature_framework_stop_node.py b/test/functional/feature_framework_stop_node.py new file mode 100755 index 00000000000000..0bf55666a341a8 --- /dev/null +++ b/test/functional/feature_framework_stop_node.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# Copyright (c) 2024-present The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +""" +Verify that when a node process fails due to a startup error, we can still call +TestNode.stop_node() without triggering knock-on errors. +""" + +from test_framework.test_node import ( + FailedToStartError, + TestNode, +) +from test_framework.util import ( + assert_raises_message, +) +from test_framework.test_framework import BitcoinTestFramework + +class FeatureFrameworkStopNode(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + # Overridden to avoid syncing non-started nodes. + def setup_network(self): + self.setup_nodes() + + # Overridden to avoid starting nodes before run_test. + def setup_nodes(self): + self.add_nodes(self.num_nodes, self.extra_args) + + def run_test(self): + # Don't use the full assert_start_raises_init_error() here, as we want + # to clean state ourselves after wait_for_rpc_connection() fails. + invalid_arg_error = "Error: Error parsing command line arguments: Invalid parameter -nonexistentarg" + assert_raises_message( + exc=FailedToStartError, + message="[node 0] bitcoind exited with status 1 during initialization. " + invalid_arg_error, + fun=BitcoinTestFramework.start_node, + self=self, + i=0, + extra_args=['-nonexistentarg'], # Intentionally trigger startup failure. + ) + assert self.nodes[0].running, \ + "The process should still be flagged as running before calling stop_node()" + self.log.info("One WARNING expected - Explicitly stopping the node to verify it completes cleanly during the test") + self.nodes[0].stop_node(expected_stderr=invalid_arg_error, avoid_exceptions=True) + +if __name__ == '__main__': + FeatureFrameworkStopNode(__file__).main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 53a28312af0250..f35c0373ddc5d7 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -406,6 +406,7 @@ 'feature_help.py', 'feature_framework_rpc_failure.py', 'feature_framework_rpc_failure_details.py', + 'feature_framework_stop_node.py', 'feature_shutdown.py', 'wallet_migration.py', 'p2p_ibd_txrelay.py',