diff options
-rw-r--r-- | meta/classes-recipe/testimage.bbclass | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/meta/classes-recipe/testimage.bbclass b/meta/classes-recipe/testimage.bbclass index b48cd96575..765184c180 100644 --- a/meta/classes-recipe/testimage.bbclass +++ b/meta/classes-recipe/testimage.bbclass | |||
@@ -18,6 +18,15 @@ inherit image-artifact-names | |||
18 | 18 | ||
19 | TESTIMAGE_AUTO ??= "0" | 19 | TESTIMAGE_AUTO ??= "0" |
20 | 20 | ||
21 | # When any test fails, TESTIMAGE_FAILED_QA ARTIFACTS will be parsed and for | ||
22 | # each entry in it, if artifact pointed by path description exists on target, | ||
23 | # it will be retrieved onto host | ||
24 | |||
25 | TESTIMAGE_FAILED_QA_ARTIFACTS ??= "\ | ||
26 | ${localstatedir}/log \ | ||
27 | ${sysconfdir}/version \ | ||
28 | ${sysconfdir}/os-release" | ||
29 | |||
21 | # You can set (or append to) TEST_SUITES in local.conf to select the tests | 30 | # You can set (or append to) TEST_SUITES in local.conf to select the tests |
22 | # which you want to run for your target. | 31 | # which you want to run for your target. |
23 | # The test names are the module names in meta/lib/oeqa/runtime/cases. | 32 | # The test names are the module names in meta/lib/oeqa/runtime/cases. |
@@ -192,6 +201,39 @@ def get_testimage_boot_patterns(d): | |||
192 | boot_patterns[flag] = flagval.encode().decode('unicode-escape') | 201 | boot_patterns[flag] = flagval.encode().decode('unicode-escape') |
193 | return boot_patterns | 202 | return boot_patterns |
194 | 203 | ||
204 | def get_artifacts_list(target, raw_list): | ||
205 | result = [] | ||
206 | # Passed list may contains patterns in paths, expand them directly on target | ||
207 | for raw_path in raw_list.split(): | ||
208 | cmd = f"for p in {raw_path}; do if [ -e $p ]; then echo $p; fi; done" | ||
209 | try: | ||
210 | status, output = target.run(cmd) | ||
211 | if status != 0 or not output: | ||
212 | raise Exception() | ||
213 | result += output.split() | ||
214 | except: | ||
215 | bb.warn(f"No file/directory matching path {raw_path}") | ||
216 | |||
217 | return result | ||
218 | |||
219 | def retrieve_test_artifacts(target, artifacts_list, target_dir): | ||
220 | import shutil | ||
221 | |||
222 | local_artifacts_dir = os.path.join(target_dir, "artifacts") | ||
223 | if os.path.isdir(local_artifacts_dir): | ||
224 | shutil.rmtree(local_artifacts_dir) | ||
225 | |||
226 | os.makedirs(local_artifacts_dir) | ||
227 | for artifact_path in artifacts_list: | ||
228 | if not os.path.isabs(artifact_path): | ||
229 | bb.warn(f"{artifact_path} is not an absolute path") | ||
230 | continue | ||
231 | try: | ||
232 | dest_dir = os.path.join(local_artifacts_dir, os.path.dirname(artifact_path[1:])) | ||
233 | os.makedirs(dest_dir, exist_ok=True) | ||
234 | target.copyFrom(artifact_path, dest_dir) | ||
235 | except: | ||
236 | bb.warn(f"Can not retrieve {artifact_path} from test target") | ||
195 | 237 | ||
196 | def testimage_main(d): | 238 | def testimage_main(d): |
197 | import os | 239 | import os |
@@ -383,6 +425,12 @@ def testimage_main(d): | |||
383 | pass | 425 | pass |
384 | results = tc.runTests() | 426 | results = tc.runTests() |
385 | complete = True | 427 | complete = True |
428 | if results.hasAnyFailingTest(): | ||
429 | artifacts_list = get_artifacts_list(tc.target, d.getVar("TESTIMAGE_FAILED_QA_ARTIFACTS")) | ||
430 | if not artifacts_list: | ||
431 | bb.warn("Could not load artifacts list, skip artifacts retrieval") | ||
432 | else: | ||
433 | retrieve_test_artifacts(tc.target, artifacts_list, get_testimage_json_result_dir(d)) | ||
386 | except (KeyboardInterrupt, BlockingIOError) as err: | 434 | except (KeyboardInterrupt, BlockingIOError) as err: |
387 | if isinstance(err, KeyboardInterrupt): | 435 | if isinstance(err, KeyboardInterrupt): |
388 | bb.error('testimage interrupted, shutting down...') | 436 | bb.error('testimage interrupted, shutting down...') |