diff options
| -rw-r--r-- | meta/lib/oeqa/core/case.py | 49 | ||||
| -rw-r--r-- | scripts/lib/resulttool/log.py | 43 | ||||
| -rw-r--r-- | scripts/lib/resulttool/resultutils.py | 45 |
3 files changed, 109 insertions, 28 deletions
diff --git a/meta/lib/oeqa/core/case.py b/meta/lib/oeqa/core/case.py index aca144e9dc..180635ac6c 100644 --- a/meta/lib/oeqa/core/case.py +++ b/meta/lib/oeqa/core/case.py | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | # SPDX-License-Identifier: MIT | 4 | # SPDX-License-Identifier: MIT |
| 5 | # | 5 | # |
| 6 | 6 | ||
| 7 | import base64 | ||
| 8 | import zlib | ||
| 7 | import unittest | 9 | import unittest |
| 8 | 10 | ||
| 9 | from oeqa.core.exception import OEQAMissingVariable | 11 | from oeqa.core.exception import OEQAMissingVariable |
| @@ -49,3 +51,50 @@ class OETestCase(unittest.TestCase): | |||
| 49 | for d in self.decorators: | 51 | for d in self.decorators: |
| 50 | d.tearDownDecorator() | 52 | d.tearDownDecorator() |
| 51 | self.tearDownMethod() | 53 | self.tearDownMethod() |
| 54 | |||
| 55 | class OEPTestResultTestCase: | ||
| 56 | """ | ||
| 57 | Mix-in class to provide functions to make interacting with extraresults for | ||
| 58 | the purposes of storing ptestresult data. | ||
| 59 | """ | ||
| 60 | @staticmethod | ||
| 61 | def _compress_log(log): | ||
| 62 | logdata = log.encode("utf-8") | ||
| 63 | logdata = zlib.compress(logdata) | ||
| 64 | logdata = base64.b64encode(logdata).decode("utf-8") | ||
| 65 | return {"compressed" : logdata} | ||
| 66 | |||
| 67 | def ptest_rawlog(self, log): | ||
| 68 | if not hasattr(self, "extraresults"): | ||
| 69 | self.extraresults = {"ptestresult.sections" : {}} | ||
| 70 | self.extraresults["ptestresult.rawlogs"] = {"log" : self._compress_log(log)} | ||
| 71 | |||
| 72 | def ptest_section(self, section, duration = None, log = None, logfile = None, exitcode = None): | ||
| 73 | if not hasattr(self, "extraresults"): | ||
| 74 | self.extraresults = {"ptestresult.sections" : {}} | ||
| 75 | |||
| 76 | sections = self.extraresults.get("ptestresult.sections") | ||
| 77 | if section not in sections: | ||
| 78 | sections[section] = {} | ||
| 79 | |||
| 80 | if log is not None: | ||
| 81 | sections[section]["log"] = self._compress_log(log) | ||
| 82 | elif logfile is not None: | ||
| 83 | with open(logfile, "r") as f: | ||
| 84 | sections[section]["log"] = self._compress_log(f.read()) | ||
| 85 | |||
| 86 | if duration is not None: | ||
| 87 | sections[section]["duration"] = duration | ||
| 88 | if exitcode is not None: | ||
| 89 | sections[section]["exitcode"] = exitcode | ||
| 90 | |||
| 91 | def ptest_result(self, section, test, result): | ||
| 92 | if not hasattr(self, "extraresults"): | ||
| 93 | self.extraresults = {"ptestresult.sections" : {}} | ||
| 94 | |||
| 95 | sections = self.extraresults.get("ptestresult.sections") | ||
| 96 | if section not in sections: | ||
| 97 | sections[section] = {} | ||
| 98 | resultname = "ptestresult.{}.{}".format(section, test) | ||
| 99 | self.extraresults[resultname] = {"status" : result} | ||
| 100 | |||
diff --git a/scripts/lib/resulttool/log.py b/scripts/lib/resulttool/log.py index 2352c767d9..f1bfd99500 100644 --- a/scripts/lib/resulttool/log.py +++ b/scripts/lib/resulttool/log.py | |||
| @@ -8,12 +8,12 @@ import os | |||
| 8 | import resulttool.resultutils as resultutils | 8 | import resulttool.resultutils as resultutils |
| 9 | 9 | ||
| 10 | def show_ptest(result, ptest, logger): | 10 | def show_ptest(result, ptest, logger): |
| 11 | if 'ptestresult.sections' in result: | 11 | logdata = resultutils.ptestresult_get_log(result, ptest) |
| 12 | if ptest in result['ptestresult.sections'] and 'log' in result['ptestresult.sections'][ptest]: | 12 | if logdata is not None: |
| 13 | print(result['ptestresult.sections'][ptest]['log']) | 13 | print(logdata) |
| 14 | return 0 | 14 | return 0 |
| 15 | 15 | ||
| 16 | print("ptest '%s' not found" % ptest) | 16 | print("ptest '%s' log not found" % ptest) |
| 17 | return 1 | 17 | return 1 |
| 18 | 18 | ||
| 19 | def show_reproducible(result, reproducible, logger): | 19 | def show_reproducible(result, reproducible, logger): |
| @@ -25,7 +25,6 @@ def show_reproducible(result, reproducible, logger): | |||
| 25 | print("reproducible '%s' not found" % reproducible) | 25 | print("reproducible '%s' not found" % reproducible) |
| 26 | return 1 | 26 | return 1 |
| 27 | 27 | ||
| 28 | |||
| 29 | def log(args, logger): | 28 | def log(args, logger): |
| 30 | results = resultutils.load_resultsdata(args.source) | 29 | results = resultutils.load_resultsdata(args.source) |
| 31 | 30 | ||
| @@ -35,24 +34,24 @@ def log(args, logger): | |||
| 35 | return 1 | 34 | return 1 |
| 36 | 35 | ||
| 37 | for _, run_name, _, r in resultutils.test_run_results(results): | 36 | for _, run_name, _, r in resultutils.test_run_results(results): |
| 38 | if args.dump_ptest: | 37 | if args.dump_ptest and 'ptestresult.sections' in r: |
| 39 | if 'ptestresult.sections' in r: | 38 | for name, ptest in r['ptestresult.sections'].items(): |
| 40 | for name, ptest in r['ptestresult.sections'].items(): | 39 | logdata = resultutils.ptestresult_get_log(r, name) |
| 41 | if 'log' in ptest: | 40 | if logdata is not None: |
| 42 | dest_dir = args.dump_ptest | 41 | dest_dir = args.dump_ptest |
| 43 | if args.prepend_run: | 42 | if args.prepend_run: |
| 44 | dest_dir = os.path.join(dest_dir, run_name) | 43 | dest_dir = os.path.join(dest_dir, run_name) |
| 45 | 44 | ||
| 46 | os.makedirs(dest_dir, exist_ok=True) | 45 | os.makedirs(dest_dir, exist_ok=True) |
| 47 | 46 | dest = os.path.join(dest_dir, '%s.log' % name) | |
| 48 | dest = os.path.join(dest_dir, '%s.log' % name) | 47 | print(dest) |
| 49 | print(dest) | 48 | with open(dest, 'w') as f: |
| 50 | with open(dest, 'w') as f: | 49 | f.write(logdata) |
| 51 | f.write(ptest['log']) | ||
| 52 | 50 | ||
| 53 | if args.raw_ptest: | 51 | if args.raw_ptest: |
| 54 | if 'ptestresult.rawlogs' in r: | 52 | rawlog = resultutils.ptestresult_get_rawlogs(r) |
| 55 | print(r['ptestresult.rawlogs']['log']) | 53 | if rawlog is not None: |
| 54 | print(rawlog) | ||
| 56 | else: | 55 | else: |
| 57 | print('Raw ptest logs not found') | 56 | print('Raw ptest logs not found') |
| 58 | return 1 | 57 | return 1 |
diff --git a/scripts/lib/resulttool/resultutils.py b/scripts/lib/resulttool/resultutils.py index e595c185df..177fb25f93 100644 --- a/scripts/lib/resulttool/resultutils.py +++ b/scripts/lib/resulttool/resultutils.py | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | # | 7 | # |
| 8 | 8 | ||
| 9 | import os | 9 | import os |
| 10 | import base64 | ||
| 11 | import zlib | ||
| 10 | import json | 12 | import json |
| 11 | import scriptpath | 13 | import scriptpath |
| 12 | import copy | 14 | import copy |
| @@ -117,6 +119,34 @@ def strip_ptestresults(results): | |||
| 117 | del newresults[res]['result']['ptestresult.sections'][i]['log'] | 119 | del newresults[res]['result']['ptestresult.sections'][i]['log'] |
| 118 | return newresults | 120 | return newresults |
| 119 | 121 | ||
| 122 | def decode_log(logdata): | ||
| 123 | if isinstance(logdata, str): | ||
| 124 | return logdata | ||
| 125 | elif isinstance(logdata, dict): | ||
| 126 | if "compressed" in logdata: | ||
| 127 | data = logdata.get("compressed") | ||
| 128 | data = base64.b64decode(data.encode("utf-8")) | ||
| 129 | return zlib.decompress(data).decode("utf-8") | ||
| 130 | return None | ||
| 131 | |||
| 132 | def ptestresult_get_log(results, section): | ||
| 133 | if 'ptestresult.sections' not in results: | ||
| 134 | return None | ||
| 135 | if section not in results['ptestresult.sections']: | ||
| 136 | return None | ||
| 137 | |||
| 138 | ptest = results['ptestresult.sections'][section] | ||
| 139 | if 'log' not in ptest: | ||
| 140 | return None | ||
| 141 | return decode_log(ptest['log']) | ||
| 142 | |||
| 143 | def ptestresult_get_rawlogs(results): | ||
| 144 | if 'ptestresult.rawlogs' not in results: | ||
| 145 | return None | ||
| 146 | if 'log' not in results['ptestresult.rawlogs']: | ||
| 147 | return None | ||
| 148 | return decode_log(results['ptestresult.rawlogs']['log']) | ||
| 149 | |||
| 120 | def save_resultsdata(results, destdir, fn="testresults.json", ptestjson=False, ptestlogs=False): | 150 | def save_resultsdata(results, destdir, fn="testresults.json", ptestjson=False, ptestlogs=False): |
| 121 | for res in results: | 151 | for res in results: |
| 122 | if res: | 152 | if res: |
| @@ -131,14 +161,17 @@ def save_resultsdata(results, destdir, fn="testresults.json", ptestjson=False, p | |||
| 131 | f.write(json.dumps(resultsout, sort_keys=True, indent=4)) | 161 | f.write(json.dumps(resultsout, sort_keys=True, indent=4)) |
| 132 | for res2 in results[res]: | 162 | for res2 in results[res]: |
| 133 | if ptestlogs and 'result' in results[res][res2]: | 163 | if ptestlogs and 'result' in results[res][res2]: |
| 134 | if 'ptestresult.rawlogs' in results[res][res2]['result']: | 164 | seriesresults = results[res][res2]['result'] |
| 165 | rawlogs = ptestresult_get_rawlogs(seriesresults) | ||
| 166 | if rawlogs is not None: | ||
| 135 | with open(dst.replace(fn, "ptest-raw.log"), "w+") as f: | 167 | with open(dst.replace(fn, "ptest-raw.log"), "w+") as f: |
| 136 | f.write(results[res][res2]['result']['ptestresult.rawlogs']['log']) | 168 | f.write(rawlogs) |
| 137 | if 'ptestresult.sections' in results[res][res2]['result']: | 169 | if 'ptestresult.sections' in seriesresults: |
| 138 | for i in results[res][res2]['result']['ptestresult.sections']: | 170 | for i in seriesresults['ptestresult.sections']: |
| 139 | if 'log' in results[res][res2]['result']['ptestresult.sections'][i]: | 171 | sectionlog = ptestresult_get_log(seriesresults, i) |
| 172 | if sectionlog is not None: | ||
| 140 | with open(dst.replace(fn, "ptest-%s.log" % i), "w+") as f: | 173 | with open(dst.replace(fn, "ptest-%s.log" % i), "w+") as f: |
| 141 | f.write(results[res][res2]['result']['ptestresult.sections'][i]['log']) | 174 | f.write(sectionlog) |
| 142 | 175 | ||
| 143 | def git_get_result(repo, tags): | 176 | def git_get_result(repo, tags): |
| 144 | git_objs = [] | 177 | git_objs = [] |
