diff mbox series

[wrynose,05/38] testimage: handle bootlog variants on failed qemu tests

Message ID e9cdd45e1c8769650b70965f99780670e219cae9.1788938909.git.yoann.congal@smile.fr
State New
Headers show
Series [wrynose,01/38] linux-yocto/6.18: update to v6.18.41 | expand

Commit Message

Yoann Congal Sept. 9, 2026, 7:29 a.m. UTC
From: Peter Tatrai <peter.tatrai.ext@siemens.com>

The failure summary path assumed the unsuffixed bootlog file always
exists and unconditionally opened it.

This is not guaranteed when SERIAL_CONSOLES has fewer than two
entries (including empty), where qemurunner can produce only
bootlog suffix variants (for example .2 or .stdout).

On test failures, collect snippets from all existing files matching
bootlog and bootlog.* and prefix each snippet with its filename.
Also skip creating a symlink for a missing bootlog path.

This prevents FileNotFoundError from masking the original test
failure and improves diagnostics across qemu serial configurations.

(From OE-Core rev: 7a6596925cb0eb8dd48a0362a51875cdd60152bc)

Signed-off-by: Peter Tatrai <peter.tatrai.ext@siemens.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Yoann Congal <yoann.congal@smile.fr>
---
 meta/classes-recipe/testimage.bbclass | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/meta/classes-recipe/testimage.bbclass b/meta/classes-recipe/testimage.bbclass
index 9902b8a5682..0f34d551e99 100644
--- a/meta/classes-recipe/testimage.bbclass
+++ b/meta/classes-recipe/testimage.bbclass
@@ -186,6 +186,7 @@  def get_testimage_boot_patterns(d):
 
 def testimage_main(d):
     import os
+    import glob
     import json
     import signal
     import logging
@@ -409,15 +410,33 @@  def testimage_main(d):
     # Copy additional logs to tmp/log/oeqa so it's easier to find them
     targetdir = os.path.join(get_json_result_dir(d), d.getVar("PN"))
     os.makedirs(targetdir, exist_ok=True)
-    os.symlink(bootlog, os.path.join(targetdir, os.path.basename(bootlog)))
+    if os.path.exists(bootlog):
+        os.symlink(bootlog, os.path.join(targetdir, os.path.basename(bootlog)))
+    else:
+        bb.note("testimage: boot log not found at %s" % bootlog)
+
     os.symlink(d.getVar("BB_LOGFILE"), os.path.join(targetdir, os.path.basename(d.getVar("BB_LOGFILE") + "." + d.getVar('DATETIME'))))
 
     if not results or not complete:
         bb.error('%s - FAILED - tests were interrupted during execution, check the logs in %s' % (pn, d.getVar("LOG_DIR")), forcelog=True)
     if results and not results.wasSuccessful():
-        with open(bootlog, 'r') as bootlogfile:
-            bootlines = "".join(bootlogfile.readlines()[-20:])
-        bb.plain('%s - FAILED - Last lines of QEMU boot log:\n%s' % (pn, bootlines))
+        bootlog_files = []
+        for candidate in [bootlog] + sorted(glob.glob(bootlog + ".*")):
+            if os.path.exists(candidate) and candidate not in bootlog_files:
+                bootlog_files.append(candidate)
+
+        if bootlog_files:
+            snippets = []
+            for bootlog_file in bootlog_files:
+                try:
+                    with open(bootlog_file, 'r') as bootlogfile:
+                        bootlines = "".join(bootlogfile.readlines()[-20:])
+                except OSError as err:
+                    bootlines = "<failed to read %s: %s>\n" % (bootlog_file, err)
+                snippets.append("--- %s ---\n%s" % (os.path.basename(bootlog_file), bootlines))
+            bb.plain('%s - FAILED - Last lines of QEMU boot logs:\n%s' % (pn, "\n".join(snippets)))
+        else:
+            bb.plain('%s - FAILED - QEMU boot logs not available at %s or %s.*' % (pn, bootlog, bootlog))
         bb.error('%s - FAILED - also check the logs in %s' % (pn, d.getVar("LOG_DIR")), forcelog=True)
 
 def get_runtime_paths(d):