···
from collections.abc import Callable, Iterator
from contextlib import AbstractContextManager, contextmanager
12
+
from unittest import TestCase
from test_driver.logger import AbstractLogger
from test_driver.machine import Machine, NixStartScript, retry
···
def pythonize_name(name: str) -> str:
return re.sub(r"^[^A-z_]|[^A-z0-9_]", "_", name)
44
+
class NixOSAssertionError(AssertionError):
48
+
class Tester(TestCase):
49
+
failureException = NixOSAssertionError
···
serial_stdout_on=self.serial_stdout_on,
polling_condition=self.polling_condition,
Machine=Machine, # for typing
machine_symbols = {pythonize_name(m.name): m for m in self.machines}
# If there's exactly one machine, make it available under the name
···
"""Run the test script"""
with self.logger.nested("run the VM test script"):
symbols = self.test_symbols() # call eagerly
166
-
exec(self.tests, symbols, None)
179
+
exec(self.tests, symbols, None)
180
+
except NixOSAssertionError:
181
+
exc_type, exc, tb = sys.exc_info()
184
+
for frame in traceback.extract_tb(tb)
185
+
if frame.filename == "<string>"
188
+
self.logger.log_test_error("Traceback (most recent call last):")
189
+
code = self.tests.splitlines()
190
+
for frame, line in zip(filtered, traceback.format_list(filtered)):
191
+
self.logger.log_test_error(line.rstrip())
192
+
if lineno := frame.lineno:
193
+
self.logger.log_test_error(
194
+
f" {code[lineno - 1].strip()}",
197
+
self.logger.log_test_error("") # blank line for readability
198
+
exc_prefix = exc_type.__name__ if exc_type is not None else "Error"
199
+
for line in f"{exc_prefix}: {exc}".splitlines():
200
+
self.logger.log_test_error(line)
def run_tests(self) -> None:
"""Run the test script (for non-interactive test runs)"""