Add a basic artifacts retrievers in testimage class which:
- triggers when at least one runtime test fails
- reads a list of files to retrieve from ARTIFACTS_LIST_PATH
- retrieve those files over scp thanks to existing ssh class
- store those files in an "artifacts" directory in "tmp/log/oeqa/<image>"

Bring partial solution to [YOCTO #14901]

Signed-off-by: Alexis Lothoré <alexis.loth...@bootlin.com>
---
 meta/classes-recipe/testimage.bbclass | 51 +++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/meta/classes-recipe/testimage.bbclass 
b/meta/classes-recipe/testimage.bbclass
index 6b10c1db09f9..3fd3dd5b0264 100644
--- a/meta/classes-recipe/testimage.bbclass
+++ b/meta/classes-recipe/testimage.bbclass
@@ -18,6 +18,12 @@ inherit image-artifact-names
 
 TESTIMAGE_AUTO ??= "0"
 
+# When any test fails, if path to an artifacts configuration (listing
+# files/directories to retrieve on target) has been provided, all listed
+# elements will be downloaded from target before shutting it down
+
+ARTIFACTS_LIST_PATH ??= ""
+
 # You can set (or append to) TEST_SUITES in local.conf to select the tests
 # which you want to run for your target.
 # The test names are the module names in meta/lib/oeqa/runtime/cases.
@@ -192,6 +198,45 @@ def get_testimage_boot_patterns(d):
                 boot_patterns[flag] = flagval.encode().decode('unicode-escape')
     return boot_patterns
 
+def load_artifacts_list(artifacts_conf_path):
+    import json
+
+    if not artifacts_conf_path:
+        return None
+
+    if not os.path.isfile(artifacts_conf_path):
+        return None
+
+    try:
+        with open(artifacts_conf_path) as f:
+            artifacts_list = json.load(f)
+    except json.decoder.JSONDecodeError as e:
+        bb.warn(f"Invalid tests artifact list format: {e.lineno}:{e.colno} : 
{e.msg}")
+        return None
+
+    if 'artifacts' in artifacts_list:
+        return artifacts_list['artifacts']
+
+    return None
+
+def retrieve_test_artifacts(target, artifacts_list, target_dir):
+    import shutil
+
+    local_artifacts_dir = os.path.join(target_dir, "artifacts")
+    if os.path.isdir(local_artifacts_dir):
+        shutil.rmtree(local_artifacts_dir)
+
+    os.makedirs(local_artifacts_dir)
+    for artifact_path in artifacts_list:
+        if not os.path.isabs(artifact_path):
+            bb.warn(f"{artifact_path} is not an absolute path")
+            continue
+        try:
+            dest_dir = os.path.join(local_artifacts_dir, 
os.path.dirname(artifact_path[1:]))
+            os.makedirs(dest_dir, exist_ok=True)
+            target.copyFrom(artifact_path, dest_dir)
+        except:
+            bb.warn(f"Can not retrieve {artifact_path} from test target")
 
 def testimage_main(d):
     import os
@@ -402,6 +447,12 @@ def testimage_main(d):
                         get_testimage_result_id(configuration),
                         dump_streams=d.getVar('TESTREPORT_FULLLOGS'))
         results.logSummary(pn)
+        if not results.wasSuccessful():
+            artifacts_list = 
load_artifacts_list(d.getVar("ARTIFACTS_LIST_PATH"))
+            if not artifacts_list:
+                bb.warn("Could not load artifacts list, skip artifacts 
retrieval")
+            else:
+                retrieve_test_artifacts(tc.target, artifacts_list, 
get_testimage_json_result_dir(d))
 
     tc.target.stop()
 
-- 
2.40.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#182300): 
https://lists.openembedded.org/g/openembedded-core/message/182300
Mute This Topic: https://lists.openembedded.org/mt/99283034/21656
Group Owner: openembedded-core+ow...@lists.openembedded.org
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to