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 shlex
import shutil import shutil
import sys import sys
from collections.abc import Iterable
from pathlib import Path from pathlib import Path
from .authproxy import ( from .authproxy import (
@@ -469,6 +470,12 @@ class TestNode():
"""Checks whether the node has stopped. """Checks whether the node has stopped.
Returns True if the node has stopped. False otherwise. 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).""" This method is responsible for freeing resources (self.process)."""
if not self.running: if not self.running:
return True return True
@@ -477,12 +484,17 @@ class TestNode():
return False return False
# process has stopped. Assert that it didn't return an error code. # 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") f"Node returned unexpected exit code ({return_code}) vs ({expected_ret_code}) when stopping")
# Check that stderr is as expected # Check that stderr is as expected
self.stderr.seek(0) self.stderr.seek(0)
stderr = self.stderr.read().decode('utf-8').strip() 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)) raise AssertionError("Unexpected stderr {} != {}".format(stderr, expected_stderr))
self.stdout.close() self.stdout.close()