test framework: expand expected_stderr, expected_ret_code options

Allow `expected_stderr` option passed to `wait_until_stopped` and
`is_node_stopped` helper functions to be a regex pattern instead of just a
fixed string.

Allow `expected_ret_code` be list of possible exit codes instead of a single
error code to handle the case where exit codes vary depending on OS and libc.
This commit is contained in:
Ryan Ofsky
2026-01-14 08:37:37 -05:00
parent df53a3e5ec
commit b970cdf20f

View File

@@ -22,6 +22,7 @@ import collections
import shlex
import shutil
import sys
from collections.abc import Iterable
from pathlib import Path
from .authproxy import (
@@ -469,6 +470,12 @@ class TestNode():
"""Checks whether the node has stopped.
Returns True if the node has stopped. False otherwise.
If the process has exited, asserts that the exit code matches
`expected_ret_code` (which may be a single value or an iterable of values),
and that stderr matches `expected_stderr` exactly or, if a regex pattern is
provided, contains the pattern.
This method is responsible for freeing resources (self.process)."""
if not self.running:
return True
@@ -477,12 +484,17 @@ class TestNode():
return False
# process has stopped. Assert that it didn't return an error code.
assert return_code == expected_ret_code, self._node_msg(
if not isinstance(expected_ret_code, Iterable):
expected_ret_code = (expected_ret_code,)
assert return_code in 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:
if isinstance(expected_stderr, re.Pattern):
if not expected_stderr.search(stderr):
raise AssertionError(f"Unexpected stderr {stderr!r} does not contain {expected_stderr.pattern!r}")
elif stderr != expected_stderr:
raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr))
self.stdout.close()