qa-tests: Log expected output in debug
What changed, and why it matters
This is a minor improvement to a Bitcoin Core test script. It adds clearer debug logging when a test child process produces the expected output, and it handles the edge case where a timeout occurs with no captured output. There is no change to the actual Bitcoin Core software that users run, and no security issue is present.
No security action needed. Treat as a normal test-quality improvement.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit modifies test/functional/feature_framework_startup_failures.py, a QA test helper. It refactors child-process output formatting, replaces a re-raised TimeoutExpired exception with sys.exit when the child times out, guards against e.output being None, updates assertion messages, and adds a self.log.debug line for expected-error cases. The change is purely in test infrastructure.
Changed components
test/functional/feature_framework_startup_failures.pyInspect captured patch +15 / −9
diff --git a/test/functional/feature_framework_startup_failures.py b/test/functional/feature_framework_startup_failures.py
index 115b36ad..ee031e11 100755
--- a/test/functional/feature_framework_startup_failures.py
+++ b/test/functional/feature_framework_startup_failures.py
@@ -36,22 +36,24 @@ class FeatureFrameworkStartupFailures(BitcoinTestFramework):
# Launches a child test process that runs this same file, but instantiates
# a child test. Verifies that it raises only the expected exception, once.
def _verify_startup_failure(self, test, internal_args, expected_exception):
+ name = test.__name__
+ def format_child_output(output):
+ return f"\n<{name} OUTPUT BEGIN>\n{output.strip()}\n<{name} OUTPUT END>\n"
+
# Inherit sys.argv from parent, only overriding tmpdir to a subdirectory
# so children don't fail due to colliding with the parent dir.
assert self.options.tmpdir, "Framework should always set tmpdir."
subdir = md5(expected_exception.encode('utf-8')).hexdigest()[:8]
- args = [sys.executable] + sys.argv + [f"--tmpdir={self.options.tmpdir}/{subdir}", f"--internal_test={test.__name__}"] + internal_args
+ args = [sys.executable] + sys.argv + [f"--tmpdir={self.options.tmpdir}/{subdir}", f"--internal_test={name}"] + internal_args
try:
output = subprocess.run(args, timeout=60 * self.options.timeout_factor,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True).stdout
except subprocess.TimeoutExpired as e:
- print("Unexpected child process timeout!\n"
- "WARNING: Timeouts like this halt execution of TestNode logic, "
- "meaning dangling bitcoind processes are to be expected.\n"
- f"<CHILD OUTPUT BEGIN>\n{e.output.decode("utf-8")}\n<CHILD OUTPUT END>",
- file=sys.stderr)
- raise
+ sys.exit("Unexpected child process timeout!\n"
+ "WARNING: Timeouts like this halt execution of TestNode logic, "
+ "meaning dangling bitcoind processes are to be expected.\n" +
+ (format_child_output(e.output.decode("utf-8")) if e.output else "<EMPTY OUTPUT>"))
errors = []
if (n := output.count("Traceback")) != 1:
@@ -61,13 +63,17 @@ class FeatureFrameworkStartupFailures(BitcoinTestFramework):
if (n := output.count("Test failed. Test logging available at")) != 1:
errors.append(f"Found {n}/1 test failure output messages.")
- assert not errors, f"Child test didn't contain (only) expected errors:\n{linesep.join(errors)}\n<CHILD OUTPUT BEGIN>\n{output}\n<CHILD OUTPUT END>\n"
+ assert not errors, (f"Child test did NOT contain (only) expected errors:\n{linesep.join(errors)}\n" +
+ format_child_output(output))
+
+ self.log.debug("Child test did contain (only) expected errors:\n" +
+ format_child_output(output))
def run_test(self):
self.log.info("Verifying _verify_startup_failure() functionality (self-check).")
assert_raises_message(
AssertionError,
- ( "Child test didn't contain (only) expected errors:\n"
+ ( "Child test did NOT contain (only) expected errors:\n"
f"Found 0/1 tracebacks - expecting exactly one with no knock-on exceptions.{linesep}"
f"Found 0/1 occurrences of the specific exception: NonExistentError{linesep}"
"Found 0/1 test failure output messages."),
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.