summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/utils/logparser.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oeqa/utils/logparser.py')
-rw-r--r--meta/lib/oeqa/utils/logparser.py98
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 @@
1# 1#
2# Copyright OpenEmbedded Contributors
3#
2# SPDX-License-Identifier: MIT 4# SPDX-License-Identifier: MIT
3# 5#
4 6
5import sys 7import enum
6import os 8import os
7import re 9import re
8 10
@@ -42,6 +44,8 @@ class PtestParser(object):
42 result = section_regex['begin'].search(line) 44 result = section_regex['begin'].search(line)
43 if result: 45 if result:
44 current_section['name'] = result.group(1) 46 current_section['name'] = result.group(1)
47 if current_section['name'] not in self.results:
48 self.results[current_section['name']] = {}
45 continue 49 continue
46 50
47 result = section_regex['end'].search(line) 51 result = section_regex['end'].search(line)
@@ -73,9 +77,10 @@ class PtestParser(object):
73 for t in test_regex: 77 for t in test_regex:
74 result = test_regex[t].search(line) 78 result = test_regex[t].search(line)
75 if result: 79 if result:
76 if current_section['name'] not in self.results: 80 try:
77 self.results[current_section['name']] = {} 81 self.results[current_section['name']][result.group(1).strip()] = t
78 self.results[current_section['name']][result.group(1).strip()] = t 82 except KeyError:
83 bb.warn("Result with no section: %s - %s" % (t, result.group(1).strip()))
79 84
80 # Python performance for repeatedly joining long strings is poor, do it all at once at the end. 85 # Python performance for repeatedly joining long strings is poor, do it all at once at the end.
81 # For 2.1 million lines in a log this reduces 18 hours to 12s. 86 # For 2.1 million lines in a log this reduces 18 hours to 12s.
@@ -101,30 +106,48 @@ class PtestParser(object):
101 f.write(status + ": " + test_name + "\n") 106 f.write(status + ": " + test_name + "\n")
102 107
103 108
104# ltp log parsing 109class LtpParser:
105class LtpParser(object): 110 """
106 def __init__(self): 111 Parse the machine-readable LTP log output into a ptest-friendly data structure.
107 self.results = {} 112 """
108 self.section = {'duration': "", 'log': ""}
109
110 def parse(self, logfile): 113 def parse(self, logfile):
111 test_regex = {} 114 results = {}
112 test_regex['PASSED'] = re.compile(r"PASS") 115 # Aaccumulate the duration here but as the log rounds quick tests down
113 test_regex['FAILED'] = re.compile(r"FAIL") 116 # to 0 seconds this is very much a lower bound. The caller can replace
114 test_regex['SKIPPED'] = re.compile(r"SKIP") 117 # the value.
115 118 section = {"duration": 0, "log": ""}
116 with open(logfile, errors='replace') as f: 119
120 class LtpExitCode(enum.IntEnum):
121 # Exit codes as defined in ltp/include/tst_res_flags.h
122 TPASS = 0 # Test passed flag
123 TFAIL = 1 # Test failed flag
124 TBROK = 2 # Test broken flag
125 TWARN = 4 # Test warning flag
126 TINFO = 16 # Test information flag
127 TCONF = 32 # Test not appropriate for configuration flag
128
129 with open(logfile, errors="replace") as f:
130 # Lines look like this:
131 # tag=cfs_bandwidth01 stime=1689762564 dur=0 exit=exited stat=32 core=no cu=0 cs=0
117 for line in f: 132 for line in f:
118 for t in test_regex: 133 if not line.startswith("tag="):
119 result = test_regex[t].search(line) 134 continue
120 if result:
121 self.results[line.split()[0].strip()] = t
122 135
123 for test in self.results: 136 values = dict(s.split("=") for s in line.strip().split())
124 result = self.results[test]
125 self.section['log'] = self.section['log'] + ("%s: %s\n" % (result.strip()[:-2], test.strip()))
126 137
127 return self.results, self.section 138 section["duration"] += int(values["dur"])
139 exitcode = int(values["stat"])
140 if values["exit"] == "exited" and exitcode == LtpExitCode.TCONF:
141 # Exited normally with the "invalid configuration" code
142 results[values["tag"]] = "SKIPPED"
143 elif exitcode == LtpExitCode.TPASS:
144 # Successful exit
145 results[values["tag"]] = "PASSED"
146 else:
147 # Other exit
148 results[values["tag"]] = "FAILED"
149
150 return results, section
128 151
129 152
130# ltp Compliance log parsing 153# ltp Compliance log parsing
@@ -135,30 +158,27 @@ class LtpComplianceParser(object):
135 158
136 def parse(self, logfile): 159 def parse(self, logfile):
137 test_regex = {} 160 test_regex = {}
138 test_regex['PASSED'] = re.compile(r"^PASS") 161 test_regex['FAILED'] = re.compile(r"FAIL")
139 test_regex['FAILED'] = re.compile(r"^FAIL")
140 test_regex['SKIPPED'] = re.compile(r"(?:UNTESTED)|(?:UNSUPPORTED)")
141 162
142 section_regex = {} 163 section_regex = {}
143 section_regex['test'] = re.compile(r"^Testing") 164 section_regex['test'] = re.compile(r"^Executing")
144 165
145 with open(logfile, errors='replace') as f: 166 with open(logfile, errors='replace') as f:
167 name = logfile
168 result = "PASSED"
146 for line in f: 169 for line in f:
147 result = section_regex['test'].search(line) 170 regex_result = section_regex['test'].search(line)
148 if result: 171 if regex_result:
149 self.name = "" 172 name = line.split()[1].strip()
150 self.name = line.split()[1].strip()
151 self.results[self.name] = "PASSED"
152 failed = 0
153 173
154 failed_result = test_regex['FAILED'].search(line) 174 regex_result = test_regex['FAILED'].search(line)
155 if failed_result: 175 if regex_result:
156 failed = line.split()[1].strip() 176 result = "FAILED"
157 if int(failed) > 0: 177 self.results[name] = result
158 self.results[self.name] = "FAILED"
159 178
160 for test in self.results: 179 for test in self.results:
161 result = self.results[test] 180 result = self.results[test]
181 print (self.results)
162 self.section['log'] = self.section['log'] + ("%s: %s\n" % (result.strip()[:-2], test.strip())) 182 self.section['log'] = self.section['log'] + ("%s: %s\n" % (result.strip()[:-2], test.strip()))
163 183
164 return self.results, self.section 184 return self.results, self.section