blob: e106f6e47db4c05f2047162b4ce91b8f771ddf15 [file] [log] [blame]
Aviv Keshet1b6ec432018-07-17 17:05:41 -07001import re
2import reason_qualifier
3
4# pylint: disable=missing-docstring
mblighbfec5222007-09-14 16:58:57 +00005
mblighcfd2d012007-09-19 21:07:34 +00006color_map = {
jadmanski0afbb632008-06-06 21:10:57 +00007 'header' : '#e5e5c0', # greyish yellow
8 'blank' : '#ffffff', # white
9 'plain_text' : '#e5e5c0', # greyish yellow
10 'borders' : '#bbbbbb', # grey
11 'white' : '#ffffff', # white
12 'green' : '#66ff66', # green
13 'yellow' : '#fffc00', # yellow
14 'red' : '#ff6666', # red
mbligh439661b2008-02-19 15:57:53 +000015
jadmanski0afbb632008-06-06 21:10:57 +000016 #### additional keys for shaded color of a box
17 #### depending on stats of GOOD/FAIL
18 '100pct' : '#32CD32', # green, 94% to 100% of success
19 '95pct' : '#c0ff80', # step twrds yellow, 88% to 94% of success
20 '90pct' : '#ffff00', # yellow, 82% to 88%
21 '85pct' : '#ffc040', # 76% to 82%
22 '75pct' : '#ff4040', # red, 1% to 76%
23 '0pct' : '#d080d0', # violet, <1% of success
mbligh439661b2008-02-19 15:57:53 +000024
mblighcfd2d012007-09-19 21:07:34 +000025}
mblighbfec5222007-09-14 16:58:57 +000026
mbligh5684b032008-06-06 14:25:35 +000027_brief_mode = False
28
29
30def set_brief_mode():
jadmanski0afbb632008-06-06 21:10:57 +000031 global _brief_mode
32 _brief_mode = True
mbligh5684b032008-06-06 14:25:35 +000033
34
35def is_brief_mode():
jadmanski0afbb632008-06-06 21:10:57 +000036 return _brief_mode
mbligh5684b032008-06-06 14:25:35 +000037
mblighcfd2d012007-09-19 21:07:34 +000038
mbligh439661b2008-02-19 15:57:53 +000039def color_keys_row():
jadmanski0afbb632008-06-06 21:10:57 +000040 """ Returns one row table with samples of 'NNpct' colors
41 defined in the color_map
42 and numbers of corresponding %%
43 """
44 ### This function does not require maintenance in case of
45 ### color_map augmenting - as long as
46 ### color keys for box shading have names that end with 'pct'
47 keys = filter(lambda key: key.endswith('pct'), color_map.keys())
48 def num_pct(key):
49 return int(key.replace('pct',''))
50 keys.sort(key=num_pct)
51 html = ''
52 for key in keys:
53 html+= "\t\t\t<td bgcolor =%s>&nbsp;&nbsp;&nbsp;</td>\n"\
54 % color_map[key]
55 hint = key.replace('pct',' %')
56 if hint[0]<>'0': ## anything but 0 %
57 hint = 'to ' + hint
58 html+= "\t\t\t<td> %s </td>\n" % hint
mbligh439661b2008-02-19 15:57:53 +000059
jadmanski0afbb632008-06-06 21:10:57 +000060 html = """
mbligh439661b2008-02-19 15:57:53 +000061<table width = "500" border="0" cellpadding="2" cellspacing="2">\n
jadmanski0afbb632008-06-06 21:10:57 +000062 <tbody>\n
63 <tr>\n
mbligh439661b2008-02-19 15:57:53 +000064%s
jadmanski0afbb632008-06-06 21:10:57 +000065 </tr>\n
66 </tbody>
mbligh439661b2008-02-19 15:57:53 +000067</table><br>
68""" % html
jadmanski0afbb632008-06-06 21:10:57 +000069 return html
mbligh439661b2008-02-19 15:57:53 +000070
mbligh5684b032008-06-06 14:25:35 +000071
72def calculate_html(link, data, tooltip=None, row_label=None, column_label=None):
jadmanski0afbb632008-06-06 21:10:57 +000073 if not is_brief_mode():
74 hover_text = '%s:%s' % (row_label, column_label)
75 if data: ## cell is not empty
76 hover_text += '<br>%s' % tooltip
77 else:
78 ## avoid "None" printed in empty cells
79 data = '&nbsp;'
80 html = ('<center><a class="info" href="%s">'
81 '%s<span>%s</span></a></center>' %
82 (link, data, hover_text))
83 return html
84 # no hover if embedded into AFE but links shall redirect to new window
85 if data: ## cell is non empty
mbligh33c77792008-12-09 23:37:02 +000086 html = '<a href="%s" target="_blank">%s</a>' % (link, data)
jadmanski0afbb632008-06-06 21:10:57 +000087 return html
88 else: ## cell is empty
89 return '&nbsp;'
mbligh5684b032008-06-06 14:25:35 +000090
mbligh439661b2008-02-19 15:57:53 +000091
mblighcfd2d012007-09-19 21:07:34 +000092class box:
jadmanski0afbb632008-06-06 21:10:57 +000093 def __init__(self, data, color_key = None, header = False, link = None,
94 tooltip = None, row_label = None, column_label = None):
mbligh5684b032008-06-06 14:25:35 +000095
jadmanski0afbb632008-06-06 21:10:57 +000096 ## in brief mode we display grid table only and nothing more
97 ## - mouse hovering feature is stubbed in brief mode
98 ## - any link opens new window or tab
mbligh439661b2008-02-19 15:57:53 +000099
jadmanski0afbb632008-06-06 21:10:57 +0000100 redirect = ""
101 if is_brief_mode():
102 ## we are acting under AFE
103 ## any link shall open new window
104 redirect = " target=NEW"
105
106 if data:
107 data = "<tt>%s</tt>" % data
108
109 if link and not tooltip:
110 ## FlipAxis corner, column and row headers
111 self.data = ('<a href="%s"%s>%s</a>' %
112 (link, redirect, data))
113 else:
114 self.data = calculate_html(link, data, tooltip,
115 row_label, column_label)
116
117 if color_map.has_key(color_key):
118 self.color = color_map[color_key]
119 elif header:
120 self.color = color_map['header']
121 elif data:
122 self.color = color_map['plain_text']
123 else:
124 self.color = color_map['blank']
125 self.header = header
mblighcfd2d012007-09-19 21:07:34 +0000126
127
jadmanski0afbb632008-06-06 21:10:57 +0000128 def html(self):
129 if self.data:
130 data = self.data
131 else:
132 data = '&nbsp'
mblighcfd2d012007-09-19 21:07:34 +0000133
jadmanski0afbb632008-06-06 21:10:57 +0000134 if self.header:
135 box_html = 'th'
136 else:
137 box_html = 'td'
mblighcfd2d012007-09-19 21:07:34 +0000138
jadmanski0afbb632008-06-06 21:10:57 +0000139 return "<%s bgcolor=%s>%s</%s>" % \
140 (box_html, self.color, data, box_html)
mblighcfd2d012007-09-19 21:07:34 +0000141
142
jamesren466640e2010-04-15 22:02:53 +0000143def grade_from_status(status_idx, status):
jadmanski0afbb632008-06-06 21:10:57 +0000144 # % of goodness
145 # GOOD (6) -> 1
146 # TEST_NA (8) is not counted
147 # ## If the test doesn't PASS, it FAILS
148 # else -> 0
mbligh439661b2008-02-19 15:57:53 +0000149
jamesren466640e2010-04-15 22:02:53 +0000150 if status == status_idx['GOOD']:
jadmanski0afbb632008-06-06 21:10:57 +0000151 return 1.0
152 else:
153 return 0.0
mbligh439661b2008-02-19 15:57:53 +0000154
155
jamesren466640e2010-04-15 22:02:53 +0000156def average_grade_from_status_count(status_idx, status_count):
jadmanski0afbb632008-06-06 21:10:57 +0000157 average_grade = 0
158 total_count = 0
159 for key in status_count.keys():
jamesren466640e2010-04-15 22:02:53 +0000160 if key not in (status_idx['TEST_NA'], status_idx['RUNNING']):
161 average_grade += (grade_from_status(status_idx, key)
jadmanski0afbb632008-06-06 21:10:57 +0000162 * status_count[key])
163 total_count += status_count[key]
164 if total_count != 0:
165 average_grade = average_grade / total_count
166 else:
167 average_grade = 0.0
168 return average_grade
mbligh439661b2008-02-19 15:57:53 +0000169
170
jamesren466640e2010-04-15 22:02:53 +0000171def shade_from_status_count(status_idx, status_count):
jadmanski0afbb632008-06-06 21:10:57 +0000172 if not status_count:
173 return None
174
175 ## average_grade defines a shade of the box
176 ## 0 -> violet
177 ## 0.76 -> red
178 ## 0.88-> yellow
179 ## 1.0 -> green
jamesren466640e2010-04-15 22:02:53 +0000180 average_grade = average_grade_from_status_count(status_idx, status_count)
jadmanski0afbb632008-06-06 21:10:57 +0000181
182 ## find appropiate keyword from color_map
183 if average_grade<0.01:
184 shade = '0pct'
185 elif average_grade<0.75:
186 shade = '75pct'
187 elif average_grade<0.85:
188 shade = '85pct'
189 elif average_grade<0.90:
190 shade = '90pct'
191 elif average_grade<0.95:
192 shade = '95pct'
193 else:
194 shade = '100pct'
195
196 return shade
mbligh439661b2008-02-19 15:57:53 +0000197
198
mbligh31260692008-04-16 23:12:12 +0000199def status_html(db, box_data, shade):
jadmanski0afbb632008-06-06 21:10:57 +0000200 """
201 status_count: dict mapping from status (integer key) to count
202 eg. { 'GOOD' : 4, 'FAIL' : 1 }
203 """
mbligh3845f522008-08-01 14:29:22 +0000204 status_count_subset = box_data.status_count.copy()
jamesren3ab001e2010-04-13 19:10:03 +0000205 test_na = db.status_idx['TEST_NA']
206 running = db.status_idx['RUNNING']
jamesren466640e2010-04-15 22:02:53 +0000207 good = db.status_idx['GOOD']
jamesren3ab001e2010-04-13 19:10:03 +0000208
209 status_count_subset[test_na] = 0 # Don't count TEST_NA
210 status_count_subset[running] = 0 # Don't count RUNNING
jamesren466640e2010-04-15 22:02:53 +0000211 html = "%d&nbsp;/&nbsp;%d " % (status_count_subset.get(good, 0),
mbligh3845f522008-08-01 14:29:22 +0000212 sum(status_count_subset.values()))
jamesren3ab001e2010-04-13 19:10:03 +0000213 if test_na in box_data.status_count.keys():
214 html += ' (%d&nbsp;N/A)' % box_data.status_count[test_na]
215 if running in box_data.status_count.keys():
216 html += ' (%d&nbsp;running)' % box_data.status_count[running]
mbligh439661b2008-02-19 15:57:53 +0000217
jadmanski0afbb632008-06-06 21:10:57 +0000218 if box_data.reasons_list:
219 reasons_list = box_data.reasons_list
220 aggregated_reasons_list = \
221 reason_qualifier.aggregate_reason_fields(reasons_list)
222 for reason in aggregated_reasons_list:
223 ## a bit of more postprocessing
224 ## to look nicer in a cell
225 ## in future: to do subtable within the cell
226 reason = reason.replace('<br>','\n')
227 reason = reason.replace('<','[').replace('>',']')
228 reason = reason.replace('|','\n').replace('&',' AND ')
229 reason = reason.replace('\n','<br>')
230 html += '<br>' + reason
mbligh31260692008-04-16 23:12:12 +0000231
jadmanski0afbb632008-06-06 21:10:57 +0000232 tooltip = ""
mbligh3845f522008-08-01 14:29:22 +0000233 for status in sorted(box_data.status_count.keys(), reverse = True):
jadmanski0afbb632008-06-06 21:10:57 +0000234 status_word = db.status_word[status]
mbligh3845f522008-08-01 14:29:22 +0000235 tooltip += "%d %s " % (box_data.status_count[status], status_word)
jadmanski0afbb632008-06-06 21:10:57 +0000236 return (html,tooltip)
mbligha997a342007-10-06 22:35:04 +0000237
238
239def status_count_box(db, tests, link = None):
jadmanski0afbb632008-06-06 21:10:57 +0000240 """
241 Display a ratio of total number of GOOD tests
242 to total number of all tests in the group of tests.
243 More info (e.g. 10 GOOD, 2 WARN, 3 FAIL) is in tooltips
244 """
245 if not tests:
246 return box(None, None)
mbligha997a342007-10-06 22:35:04 +0000247
jadmanski0afbb632008-06-06 21:10:57 +0000248 status_count = {}
249 for test in tests:
250 count = status_count.get(test.status_num, 0)
251 status_count[test.status_num] = count + 1
252 return status_precounted_box(db, status_count, link)
mbligh83f63a02007-12-12 19:13:04 +0000253
254
jadmanskif9fa4272008-05-02 15:43:33 +0000255def status_precounted_box(db, box_data, link = None,
jadmanski0afbb632008-06-06 21:10:57 +0000256 x_label = None, y_label = None):
257 """
258 Display a ratio of total number of GOOD tests
259 to total number of all tests in the group of tests.
260 More info (e.g. 10 GOOD, 2 WARN, 3 FAIL) is in tooltips
261 """
262 status_count = box_data.status_count
263 if not status_count:
264 return box(None, None)
265
jamesren466640e2010-04-15 22:02:53 +0000266 shade = shade_from_status_count(db.status_idx, status_count)
jadmanski0afbb632008-06-06 21:10:57 +0000267 html,tooltip = status_html(db, box_data, shade)
268 precounted_box = box(html, shade, False, link, tooltip,
269 x_label, y_label)
270 return precounted_box
mbligha997a342007-10-06 22:35:04 +0000271
mbligh31260692008-04-16 23:12:12 +0000272
mblighcfd2d012007-09-19 21:07:34 +0000273def print_table(matrix):
jadmanski0afbb632008-06-06 21:10:57 +0000274 """
275 matrix: list of lists of boxes, giving a matrix of data
276 Each of the inner lists is a row, not a column.
mblighcfd2d012007-09-19 21:07:34 +0000277
jadmanski0afbb632008-06-06 21:10:57 +0000278 Display the given matrix of data as a table.
279 """
mblighcfd2d012007-09-19 21:07:34 +0000280
jadmanski0afbb632008-06-06 21:10:57 +0000281 print ('<table bgcolor="%s" cellspacing="1" cellpadding="5" '
282 'style="margin-right: 200px;">') % (
283 color_map['borders'])
284 for row in matrix:
285 print '<tr>'
286 for element in row:
287 print element.html()
288 print '</tr>'
289 print '</table>'
mblighcfd2d012007-09-19 21:07:34 +0000290
291
mblighcfd2d012007-09-19 21:07:34 +0000292def sort_tests(tests):
jadmanski0afbb632008-06-06 21:10:57 +0000293 kernel_order = ['patch', 'config', 'build', 'mkinitrd', 'install']
mblighcfd2d012007-09-19 21:07:34 +0000294
jadmanski0afbb632008-06-06 21:10:57 +0000295 results = []
296 for kernel_op in kernel_order:
297 test = 'kernel.' + kernel_op
298 if tests.count(test):
299 results.append(test)
300 tests.remove(test)
301 if tests.count('boot'):
302 results.append('boot')
303 tests.remove('boot')
304 return results + sorted(tests)
mblighbfec5222007-09-14 16:58:57 +0000305
mbligh04598752007-10-01 15:49:58 +0000306
307def print_main_header():
jadmanski0afbb632008-06-06 21:10:57 +0000308 hover_css="""\
jadmanskif9fa4272008-05-02 15:43:33 +0000309a.info{
jadmanski0afbb632008-06-06 21:10:57 +0000310position:relative; /*this is the key*/
311z-index:1
312color:#000;
313text-decoration:none}
jadmanskif9fa4272008-05-02 15:43:33 +0000314
315a.info:hover{z-index:25;}
316
317a.info span{display: none}
318
319a.info:hover span{ /*the span will display just on :hover state*/
jadmanski0afbb632008-06-06 21:10:57 +0000320display:block;
321position:absolute;
322top:1em; left:1em;
323min-width: 100px;
324overflow: visible;
325border:1px solid #036;
326background-color:#fff; color:#000;
327text-align: left
jadmanskif9fa4272008-05-02 15:43:33 +0000328}
329"""
jadmanski0afbb632008-06-06 21:10:57 +0000330 print '<head><style type="text/css">'
331 print 'a { text-decoration: none }'
332 print hover_css
333 print '</style></head>'
334 print '<h2>'
335 print '<a href="compose_query.cgi">Functional</a>'
336 print '&nbsp&nbsp&nbsp'
mbligh7a41a862007-11-30 17:44:24 +0000337
338
339def group_name(group):
jadmanski0afbb632008-06-06 21:10:57 +0000340 name = re.sub('_', '<br>', group.name)
341 if re.search('/', name):
342 (owner, machine) = name.split('/', 1)
343 name = owner + '<br>' + machine
344 return name
mblighc3c8eab2009-01-21 18:50:57 +0000345
346def print_add_test_form(available_params, attributes, cleared):
347 print '<form method="post">'
348 print '<input type="hidden" name="attributes" value="%s" />' % attributes
349 print '<input type="hidden" name="cleared" value="%s" />' % cleared
350 print '<select name="key">'
351 for text in available_params:
352 print '<option value="%s">%s</option>' % (text, text)
353 print '</select>'
354 print '<input type="submit" name="add" value="Add test" />'
355 print '<input type="submit" name="clear" value="Clear all tests" />'
356 print '<input type="submit" name="reset" value="Reset" />'
357 print '</form>'