diff options
Diffstat (limited to 'meta/lib/oeqa/utils/logparser.py')
-rw-r--r-- | meta/lib/oeqa/utils/logparser.py | 98 |
1 files changed, 59 insertions, 39 deletions
diff --git a/meta/lib/oeqa/utils/logparser.py b/meta/lib/oeqa/utils/logparser.py index 60e16d500e..496d9e0c90 100644 --- a/meta/lib/oeqa/utils/logparser.py +++ b/meta/lib/oeqa/utils/logparser.py @@ -1,8 +1,10 @@ # +# Copyright OpenEmbedded Contributors +# # SPDX-License-Identifier: MIT # -import sys +import enum import os import re @@ -42,6 +44,8 @@ class PtestParser(object): result = section_regex['begin'].search(line) if result: current_section['name'] = result.group(1) + if current_section['name'] not in self.results: + self.results[current_section['name']] = {} continue result = section_regex['end'].search(line) @@ -73,9 +77,10 @@ class PtestParser(object): for t in test_regex: result = test_regex[t].search(line) if result: - if current_section['name'] not in self.results: - self.results[current_section['name']] = {} - self.results[current_section['name']][result.group(1).strip()] = t + try: + self.results[current_section['name']][result.group(1).strip()] = t + except KeyError: + bb.warn("Result with no section: %s - %s" % (t, result.group(1).strip())) # Python performance for repeatedly joining long strings is poor, do it all at once at the end. # For 2.1 million lines in a log this reduces 18 hours to 12s. @@ -101,30 +106,48 @@ class PtestParser(object): f.write(status + ": " + test_name + "\n") -# ltp log parsing -class LtpParser(object): - def __init__(self): - self.results = {} - self.section = {'duration': "", 'log': ""} - +class LtpParser: + """ + Parse the machine-readable LTP log output into a ptest-friendly data structure. + """ def parse(self, logfile): - test_regex = {} - test_regex['PASSED'] = re.compile(r"PASS") - test_regex['FAILED'] = re.compile(r"FAIL") - test_regex['SKIPPED'] = re.compile(r"SKIP") - - with open(logfile, errors='replace') as f: + results = {} + # Aaccumulate the duration here but as the log rounds quick tests down + # to 0 seconds this is very much a lower bound. The caller can replace + # the value. + section = {"duration": 0, "log": ""} + + class LtpExitCode(enum.IntEnum): + # Exit codes as defined in ltp/include/tst_res_flags.h + TPASS = 0 # Test passed flag + TFAIL = 1 # Test failed flag + TBROK = 2 # Test broken flag + TWARN = 4 # Test warning flag + TINFO = 16 # Test information flag + TCONF = 32 # Test not appropriate for configuration flag + + with open(logfile, errors="replace") as f: + # Lines look like this: + # tag=cfs_bandwidth01 stime=1689762564 dur=0 exit=exited stat=32 core=no cu=0 cs=0 for line in f: - for t in test_regex: - result = test_regex[t].search(line) - if result: - self.results[line.split()[0].strip()] = t + if not line.startswith("tag="): + continue - for test in self.results: - result = self.results[test] - self.section['log'] = self.section['log'] + ("%s: %s\n" % (result.strip()[:-2], test.strip())) + values = dict(s.split("=") for s in line.strip().split()) - return self.results, self.section + section["duration"] += int(values["dur"]) + exitcode = int(values["stat"]) + if values["exit"] == "exited" and exitcode == LtpExitCode.TCONF: + # Exited normally with the "invalid configuration" code + results[values["tag"]] = "SKIPPED" + elif exitcode == LtpExitCode.TPASS: + # Successful exit + results[values["tag"]] = "PASSED" + else: + # Other exit + results[values["tag"]] = "FAILED" + + return results, section # ltp Compliance log parsing @@ -135,30 +158,27 @@ class LtpComplianceParser(object): def parse(self, logfile): test_regex = {} - test_regex['PASSED'] = re.compile(r"^PASS") - test_regex['FAILED'] = re.compile(r"^FAIL") - test_regex['SKIPPED'] = re.compile(r"(?:UNTESTED)|(?:UNSUPPORTED)") + test_regex['FAILED'] = re.compile(r"FAIL") section_regex = {} - section_regex['test'] = re.compile(r"^Testing") + section_regex['test'] = re.compile(r"^Executing") with open(logfile, errors='replace') as f: + name = logfile + result = "PASSED" for line in f: - result = section_regex['test'].search(line) - if result: - self.name = "" - self.name = line.split()[1].strip() - self.results[self.name] = "PASSED" - failed = 0 + regex_result = section_regex['test'].search(line) + if regex_result: + name = line.split()[1].strip() - failed_result = test_regex['FAILED'].search(line) - if failed_result: - failed = line.split()[1].strip() - if int(failed) > 0: - self.results[self.name] = "FAILED" + regex_result = test_regex['FAILED'].search(line) + if regex_result: + result = "FAILED" + self.results[name] = result for test in self.results: result = self.results[test] + print (self.results) self.section['log'] = self.section['log'] + ("%s: %s\n" % (result.strip()[:-2], test.strip())) return self.results, self.section |