From dbaaef7dbfe3a932279c2d77f056a30575cc97cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:29 +0000 Subject: tests/functional: automatically clean up scratch files after tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The build/tests/functional subdirectories are consuming huge amounts of disk space. Split the location for scratch files into a 'scratch' sub-directory, separate from log files, and delete it upon completion of each test. The new env variable QEMU_TEST_KEEP_SCRATCH can be set to preserve this scratch dir for debugging access if required. Reviewed-by: Alex Bennée Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-3-berrange@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-3-alex.bennee@linaro.org> --- tests/functional/qemu_test/testcase.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index 411978b..b9418e2 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -13,8 +13,9 @@ import logging import os -import subprocess import pycotap +import shutil +import subprocess import sys import unittest import uuid @@ -40,11 +41,12 @@ class QemuBaseTest(unittest.TestCase): self.assertIsNotNone(self.qemu_bin, 'QEMU_TEST_QEMU_BINARY must be set') self.arch = self.qemu_bin.split('-')[-1] - self.workdir = os.path.join(BUILD_DIR, 'tests/functional', self.arch, - self.id()) + self.outputdir = os.path.join(BUILD_DIR, 'tests', 'functional', + self.arch, self.id()) + self.workdir = os.path.join(self.outputdir, 'scratch') os.makedirs(self.workdir, exist_ok=True) - self.logdir = self.workdir + self.logdir = self.outputdir self.log_filename = os.path.join(self.logdir, 'base.log') self.log = logging.getLogger('qemu-test') self.log.setLevel(logging.DEBUG) @@ -56,6 +58,8 @@ class QemuBaseTest(unittest.TestCase): self.log.addHandler(self._log_fh) def tearDown(self): + if "QEMU_TEST_KEEP_SCRATCH" not in os.environ: + shutil.rmtree(self.workdir) self.log.removeHandler(self._log_fh) def main(): @@ -108,7 +112,7 @@ class QemuSystemTest(QemuBaseTest): console_log = logging.getLogger('console') console_log.setLevel(logging.DEBUG) - self.console_log_name = os.path.join(self.workdir, 'console.log') + self.console_log_name = os.path.join(self.logdir, 'console.log') self._console_log_fh = logging.FileHandler(self.console_log_name, mode='w') self._console_log_fh.setLevel(logging.DEBUG) -- cgit v1.1 From 57e504ad4f0cc2037aebf18b1ca6f73c8a4b304b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:33 +0000 Subject: tests/functional: remove obsolete reference to avocado bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Historical bugs in avocado related to zstd support are not relevant to the code now that it uses QEMU's native test harness. Reviewed-by: Alex Bennée Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-7-berrange@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-7-alex.bennee@linaro.org> --- tests/functional/qemu_test/tuxruntest.py | 1 - 1 file changed, 1 deletion(-) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index f05aa96..ed2b238 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -39,7 +39,6 @@ class TuxRunBaselineTest(QemuSystemTest): super().setUp() # We need zstd for all the tuxrun tests - # See https://github.com/avocado-framework/avocado/issues/5609 (has_zstd, msg) = has_cmd('zstd') if has_zstd is False: self.skipTest(msg) -- cgit v1.1 From e6d69e0f3b83b7c60d024f41f5eaf130755b090c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:36 +0000 Subject: tests/functional: put QEMUMachine logs in testcase log directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are not passing the 'log_dir' parameter to QEMUMachine, so the QEMU stdout/err logs are being placed in a temp directory and thus deleted after execution. This makes them inaccessible as gitlab CI artifacts. Pass the testcase log directory path into QEMUMachine to make the logs persistent. Reviewed-by: Alex Bennée Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-10-berrange@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-10-alex.bennee@linaro.org> --- tests/functional/qemu_test/testcase.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index b9418e2..ca13af2 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -163,10 +163,11 @@ class QemuSystemTest(QemuBaseTest): self.skipTest('no support for device ' + devicename) def _new_vm(self, name, *args): - vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir) + vm = QEMUMachine(self.qemu_bin, + base_temp_dir=self.workdir, + log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) - self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir) if args: vm.add_args(*args) return vm -- cgit v1.1 From 9f85aff93f5dcedb70819a5ed7796b6df90fdf2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:37 +0000 Subject: tests/functional: honour requested test VM name in QEMUMachine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functional test case class is going to the trouble of passing around a machine name, but then fails to give this QEMUMachine. As a result, QEMUMachine will create a completely random name. Since log file names match the machine name, this results in log files accumulating over time. Reviewed-by: Thomas Huth Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-11-berrange@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-11-alex.bennee@linaro.org> --- tests/functional/qemu_test/testcase.py | 1 + 1 file changed, 1 insertion(+) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index ca13af2..f9c9de1 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -164,6 +164,7 @@ class QemuSystemTest(QemuBaseTest): def _new_vm(self, name, *args): vm = QEMUMachine(self.qemu_bin, + name=name, base_temp_dir=self.workdir, log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) -- cgit v1.1 From 9bcfead1ee1c5d37c39b129557e1528879270fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:38 +0000 Subject: tests/functional: enable debug logging for QEMUMachine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the 'qemu.machine' logger to 'DEBUG' level, to ensure we see log messages related to the QEMUMachine class. Most importantly this ensures we capture the full QEMU command line args for instances we spawn. Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-12-berrange@redhat.com> Tested-by: Thomas Huth Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Reviewed-by: Thomas Huth Message-Id: <20241121165806.476008-12-alex.bennee@linaro.org> --- tests/functional/qemu_test/testcase.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index f9c9de1..e2a329c 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -57,9 +57,15 @@ class QemuBaseTest(unittest.TestCase): self._log_fh.setFormatter(fileFormatter) self.log.addHandler(self._log_fh) + # Capture QEMUMachine logging + self.machinelog = logging.getLogger('qemu.machine') + self.machinelog.setLevel(logging.DEBUG) + self.machinelog.addHandler(self._log_fh) + def tearDown(self): if "QEMU_TEST_KEEP_SCRATCH" not in os.environ: shutil.rmtree(self.workdir) + self.machinelog.removeHandler(self._log_fh) self.log.removeHandler(self._log_fh) def main(): -- cgit v1.1 From 6f0942b723df9441fe3304e8ab6d87bb17f88a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:39 +0000 Subject: tests/functional: logs details of console interaction operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When functional tests go wrong, it will often be related to the console interaction wait state. By logging the messages that we're looking for, and data we're about to be sending, it'll be easier to diagnose where tests are getting stuck. Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-13-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-13-alex.bennee@linaro.org> --- tests/functional/qemu_test/cmd.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index cbabb1c..98722a9 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -85,6 +85,9 @@ def _console_interaction(test, success_message, failure_message, vm = test.vm console = vm.console_file console_logger = logging.getLogger('console') + test.log.debug( + f"Console interaction: success_msg='{success_message}' " + + f"failure_msg='{failure_message}' send_string='{send_string}'") while True: if send_string: vm.console_socket.sendall(send_string.encode()) -- cgit v1.1 From f03a81897db14bb56109b6adc8699a91774b3389 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:41 +0000 Subject: tests/functional: require non-NULL success_message for console wait MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When waiting for expected output, the 'success_message' is a mandatory parameter, with 'failure_message' defaulting to None. The code has logic which indicates it was trying to cope with 'success_message' being None and 'failure_message' being non-None but it does not appear able to actually do anything useful. The check for 'success_message is None' will break out of the loop before any check for 'failure_message' has been performed. IOW, for practcal purposes 'success_message' must be non-None unless 'send_string' is set. Assert this expectation and simplify the loop logic. Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-15-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-15-alex.bennee@linaro.org> --- tests/functional/qemu_test/cmd.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index 98722a9..f6c4e4d 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -81,6 +81,8 @@ def is_readable_executable_file(path): def _console_interaction(test, success_message, failure_message, send_string, keep_sending=False, vm=None): assert not keep_sending or send_string + assert success_message or send_string + if vm is None: vm = test.vm console = vm.console_file @@ -95,7 +97,7 @@ def _console_interaction(test, success_message, failure_message, send_string = None # send only once # Only consume console output if waiting for something - if success_message is None and failure_message is None: + if success_message is None: if send_string is None: break continue @@ -107,7 +109,7 @@ def _console_interaction(test, success_message, failure_message, if not msg: continue console_logger.debug(msg) - if success_message is None or success_message in msg: + if success_message in msg: break if failure_message and failure_message in msg: console.close() @@ -138,6 +140,7 @@ def interrupt_interactive_console_until_pattern(test, success_message, :param interrupt_string: a string to send to the console before trying to read a new line """ + assert success_message _console_interaction(test, success_message, failure_message, interrupt_string, True) @@ -152,6 +155,7 @@ def wait_for_console_pattern(test, success_message, failure_message=None, :param success_message: if this message appears, test succeeds :param failure_message: if this message appears, test fails """ + assert success_message _console_interaction(test, success_message, failure_message, None, vm=vm) def exec_command(test, command): @@ -180,6 +184,7 @@ def exec_command_and_wait_for_pattern(test, command, :param success_message: if this message appears, test succeeds :param failure_message: if this message appears, test fails """ + assert success_message _console_interaction(test, success_message, failure_message, command + '\r') def get_qemu_img(test): -- cgit v1.1 From cdad03b74f759857d784e074755f0d96a64d69af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:42 +0000 Subject: tests/functional: rewrite console handling to be bytewise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The console interaction that waits for predicted strings uses readline(), and thus is only capable of waiting for strings that are followed by a newline. This is inconvenient when needing to match on some things, particularly login prompts, or shell prompts, causing tests to use time.sleep(...) instead, which is unreliable. Switch to reading the console 1 byte at a time, comparing against the success/failure messages until we see a match, regardless of whether a newline is encountered. The success/failure comparisons are done with the python bytes type, rather than strings, to avoid the problem of needing to decode partially received multibyte utf8 characters. Heavily inspired by a patch proposed by Cédric, but written again to work in bytes, rather than strings. Co-developed-by: Cédric Le Goater Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-16-berrange@redhat.com> Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-16-alex.bennee@linaro.org> --- tests/functional/qemu_test/cmd.py | 79 +++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 15 deletions(-) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/cmd.py b/tests/functional/qemu_test/cmd.py index f6c4e4d..11c8334 100644 --- a/tests/functional/qemu_test/cmd.py +++ b/tests/functional/qemu_test/cmd.py @@ -78,6 +78,54 @@ def run_cmd(args): def is_readable_executable_file(path): return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK) +# @test: functional test to fail if @failure is seen +# @vm: the VM whose console to process +# @success: a non-None string to look for +# @failure: a string to look for that triggers test failure, or None +# +# Read up to 1 line of text from @vm, looking for @success +# and optionally @failure. +# +# If @success or @failure are seen, immediately return True, +# even if end of line is not yet seen. ie remainder of the +# line is left unread. +# +# If end of line is seen, with neither @success or @failure +# return False +# +# If @failure is seen, then mark @test as failed +def _console_read_line_until_match(test, vm, success, failure): + msg = bytes([]) + done = False + while True: + c = vm.console_socket.recv(1) + if c is None: + done = True + test.fail( + f"EOF in console, expected '{success}'") + break + msg += c + + if success in msg: + done = True + break + if failure and failure in msg: + done = True + vm.console_socket.close() + test.fail( + f"'{failure}' found in console, expected '{success}'") + + if c == b'\n': + break + + console_logger = logging.getLogger('console') + try: + console_logger.debug(msg.decode().strip()) + except: + console_logger.debug(msg) + + return done + def _console_interaction(test, success_message, failure_message, send_string, keep_sending=False, vm=None): assert not keep_sending or send_string @@ -85,11 +133,22 @@ def _console_interaction(test, success_message, failure_message, if vm is None: vm = test.vm - console = vm.console_file - console_logger = logging.getLogger('console') + test.log.debug( f"Console interaction: success_msg='{success_message}' " + f"failure_msg='{failure_message}' send_string='{send_string}'") + + # We'll process console in bytes, to avoid having to + # deal with unicode decode errors from receiving + # partial utf8 byte sequences + success_message_b = None + if success_message is not None: + success_message_b = success_message.encode() + + failure_message_b = None + if failure_message is not None: + failure_message_b = failure_message.encode() + while True: if send_string: vm.console_socket.sendall(send_string.encode()) @@ -102,20 +161,10 @@ def _console_interaction(test, success_message, failure_message, break continue - try: - msg = console.readline().decode().strip() - except UnicodeDecodeError: - msg = None - if not msg: - continue - console_logger.debug(msg) - if success_message in msg: + if _console_read_line_until_match(test, vm, + success_message_b, + failure_message_b): break - if failure_message and failure_message in msg: - console.close() - fail = 'Failure message found in console: "%s". Expected: "%s"' % \ - (failure_message, success_message) - test.fail(fail) def interrupt_interactive_console_until_pattern(test, success_message, failure_message=None, -- cgit v1.1 From 97d79319f0475fe248962166d9ec4ecf6477d8cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:43 +0000 Subject: tests/functional: remove time.sleep usage from tuxrun tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tuxrun tests send a series of strings to the guest to login and then run commands. Since we have been unable to match on console output that isn't followed by a newline, the test used many time.sleep() statements to pretend to synchronize with the guest. This has proved to be unreliable for the aarch64be instance of the tuxrun tests, with the test often hanging. The hang is a very subtle timing problem, and it is suspected that some (otherwise apparently harmless) I/O error messages could be resulting in full FIFO buffers, stalling interaction with the guest. With the newly rewritten console interaction able to match strings that don't have a following newline, the tux run tests can now match directly on the login prompt, and/or shell PS1 prompt. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2689 Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-17-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-17-alex.bennee@linaro.org> --- tests/functional/qemu_test/tuxruntest.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index ed2b238..ab3b27d 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -124,16 +124,12 @@ class TuxRunBaselineTest(QemuSystemTest): then do a few things on the console. Trigger a shutdown and wait to exit cleanly. """ - self.wait_for_console_pattern("Welcome to TuxTest") - time.sleep(0.2) - exec_command(self, 'root') - time.sleep(0.2) - exec_command(self, 'cat /proc/interrupts') - time.sleep(0.1) - exec_command(self, 'cat /proc/self/maps') - time.sleep(0.1) - exec_command(self, 'uname -a') - time.sleep(0.1) + ps1='root@tuxtest:~#' + self.wait_for_console_pattern('tuxtest login:') + exec_command_and_wait_for_pattern(self, 'root', ps1) + exec_command_and_wait_for_pattern(self, 'cat /proc/interrupts', ps1) + exec_command_and_wait_for_pattern(self, 'cat /proc/self/maps', ps1) + exec_command_and_wait_for_pattern(self, 'uname -a', ps1) exec_command_and_wait_for_pattern(self, 'halt', haltmsg) # Wait for VM to shut down gracefully if it can -- cgit v1.1 From 1a8755a51eef11360af92adf71fed6a20a1260b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:44 +0000 Subject: tests/functional: add a QMP backdoor for debugging stalled tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support the QEMU_TEST_QMP_BACKDOOR=backdoor.sock env variable as a way to get a QMP backdoor for debugging a stalled QEMU test. Most typically this would be used if running the tests directly: $ QEMU_TEST_QMP_BACKDOOR=backdoor.sock \ QEMU_TEST_QEMU_BINARY=./build/qemu-system-arm \ PYTHONPATH=./python \ ./tests/functional/test_arm_tuxrun.py And then, when the test stalls, in a second shell run: $ ./scripts/qmp/qmp-shell backdoor.sock Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-18-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-18-alex.bennee@linaro.org> --- tests/functional/qemu_test/testcase.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index e2a329c..fceafb3 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -175,6 +175,13 @@ class QemuSystemTest(QemuBaseTest): log_dir=self.logdir) self.log.debug('QEMUMachine "%s" created', name) self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) + + sockpath = os.environ.get("QEMU_TEST_QMP_BACKDOOR", None) + if sockpath is not None: + vm.add_args("-chardev", + f"socket,id=backdoor,path={sockpath},server=on,wait=off", + "-mon", "chardev=backdoor,mode=control") + if args: vm.add_args(*args) return vm -- cgit v1.1 From f5578e427f95cb34436a18c0cd4417d4280e61bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 21 Nov 2024 16:57:45 +0000 Subject: tests/functional: avoid accessing log_filename on earlier failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a failure occurs early in the QemuBaseTest constructor, the 'log_filename' object atttribute may not exist yet. This happens most notably if the QEMU_TEST_QEMU_BINARY is not set. We can't initialize 'log_filename' earlier as we use the binary to identify the architecture which is then used to build the path in which the logs are stored. Signed-off-by: Daniel P. Berrangé Message-Id: <20241121154218.1423005-19-berrange@redhat.com> Reviewed-by: Thomas Huth Signed-off-by: Alex Bennée Message-Id: <20241121165806.476008-19-alex.bennee@linaro.org> --- tests/functional/qemu_test/testcase.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'tests/functional/qemu_test') diff --git a/tests/functional/qemu_test/testcase.py b/tests/functional/qemu_test/testcase.py index fceafb3..90ae59e 100644 --- a/tests/functional/qemu_test/testcase.py +++ b/tests/functional/qemu_test/testcase.py @@ -81,10 +81,12 @@ class QemuBaseTest(unittest.TestCase): res = unittest.main(module = None, testRunner = tr, exit = False, argv=["__dummy__", path]) for (test, message) in res.result.errors + res.result.failures: - print('More information on ' + test.id() + ' could be found here:' - '\n %s' % test.log_filename, file=sys.stderr) - if hasattr(test, 'console_log_name'): - print(' %s' % test.console_log_name, file=sys.stderr) + + if hasattr(test, "log_filename"): + print('More information on ' + test.id() + ' could be found here:' + '\n %s' % test.log_filename, file=sys.stderr) + if hasattr(test, 'console_log_name'): + print(' %s' % test.console_log_name, file=sys.stderr) sys.exit(not res.result.wasSuccessful()) -- cgit v1.1