blob: c4c6cf0ab162b7173b0380dce55c58096f794b5c [file] [log] [blame]
mblighbcb2a862008-06-06 14:22:41 +00001import os, re, string, sys
2import frontend, reason_qualifier
mblighbfec5222007-09-14 16:58:57 +00003
mblighcfd2d012007-09-19 21:07:34 +00004color_map = {
jadmanski0afbb632008-06-06 21:10:57 +00005 'header' : '#e5e5c0', # greyish yellow
6 'blank' : '#ffffff', # white
7 'plain_text' : '#e5e5c0', # greyish yellow
8 'borders' : '#bbbbbb', # grey
9 'white' : '#ffffff', # white
10 'green' : '#66ff66', # green
11 'yellow' : '#fffc00', # yellow
12 'red' : '#ff6666', # red
mbligh439661b2008-02-19 15:57:53 +000013
jadmanski0afbb632008-06-06 21:10:57 +000014 #### additional keys for shaded color of a box
15 #### depending on stats of GOOD/FAIL
16 '100pct' : '#32CD32', # green, 94% to 100% of success
17 '95pct' : '#c0ff80', # step twrds yellow, 88% to 94% of success
18 '90pct' : '#ffff00', # yellow, 82% to 88%
19 '85pct' : '#ffc040', # 76% to 82%
20 '75pct' : '#ff4040', # red, 1% to 76%
21 '0pct' : '#d080d0', # violet, <1% of success
mbligh439661b2008-02-19 15:57:53 +000022
mblighcfd2d012007-09-19 21:07:34 +000023}
mblighbfec5222007-09-14 16:58:57 +000024
mbligh5684b032008-06-06 14:25:35 +000025_brief_mode = False
26
27
28def set_brief_mode():
jadmanski0afbb632008-06-06 21:10:57 +000029 global _brief_mode
30 _brief_mode = True
mbligh5684b032008-06-06 14:25:35 +000031
32
33def is_brief_mode():
jadmanski0afbb632008-06-06 21:10:57 +000034 return _brief_mode
mbligh5684b032008-06-06 14:25:35 +000035
mblighcfd2d012007-09-19 21:07:34 +000036
mbligh439661b2008-02-19 15:57:53 +000037def color_keys_row():
jadmanski0afbb632008-06-06 21:10:57 +000038 """ Returns one row table with samples of 'NNpct' colors
39 defined in the color_map
40 and numbers of corresponding %%
41 """
42 ### This function does not require maintenance in case of
43 ### color_map augmenting - as long as
44 ### color keys for box shading have names that end with 'pct'
45 keys = filter(lambda key: key.endswith('pct'), color_map.keys())
46 def num_pct(key):
47 return int(key.replace('pct',''))
48 keys.sort(key=num_pct)
49 html = ''
50 for key in keys:
51 html+= "\t\t\t<td bgcolor =%s>&nbsp;&nbsp;&nbsp;</td>\n"\
52 % color_map[key]
53 hint = key.replace('pct',' %')
54 if hint[0]<>'0': ## anything but 0 %
55 hint = 'to ' + hint
56 html+= "\t\t\t<td> %s </td>\n" % hint
mbligh439661b2008-02-19 15:57:53 +000057
jadmanski0afbb632008-06-06 21:10:57 +000058 html = """
mbligh439661b2008-02-19 15:57:53 +000059<table width = "500" border="0" cellpadding="2" cellspacing="2">\n
jadmanski0afbb632008-06-06 21:10:57 +000060 <tbody>\n
61 <tr>\n
mbligh439661b2008-02-19 15:57:53 +000062%s
jadmanski0afbb632008-06-06 21:10:57 +000063 </tr>\n
64 </tbody>
mbligh439661b2008-02-19 15:57:53 +000065</table><br>
66""" % html
jadmanski0afbb632008-06-06 21:10:57 +000067 return html
mbligh439661b2008-02-19 15:57:53 +000068
mbligh5684b032008-06-06 14:25:35 +000069
70def calculate_html(link, data, tooltip=None, row_label=None, column_label=None):
jadmanski0afbb632008-06-06 21:10:57 +000071 if not is_brief_mode():
72 hover_text = '%s:%s' % (row_label, column_label)
73 if data: ## cell is not empty
74 hover_text += '<br>%s' % tooltip
75 else:
76 ## avoid "None" printed in empty cells
77 data = '&nbsp;'
78 html = ('<center><a class="info" href="%s">'
79 '%s<span>%s</span></a></center>' %
80 (link, data, hover_text))
81 return html
82 # no hover if embedded into AFE but links shall redirect to new window
83 if data: ## cell is non empty
mbligh33c77792008-12-09 23:37:02 +000084 html = '<a href="%s" target="_blank">%s</a>' % (link, data)
jadmanski0afbb632008-06-06 21:10:57 +000085 return html
86 else: ## cell is empty
87 return '&nbsp;'
mbligh5684b032008-06-06 14:25:35 +000088
mbligh439661b2008-02-19 15:57:53 +000089
mblighcfd2d012007-09-19 21:07:34 +000090class box:
jadmanski0afbb632008-06-06 21:10:57 +000091 def __init__(self, data, color_key = None, header = False, link = None,
92 tooltip = None, row_label = None, column_label = None):
mbligh5684b032008-06-06 14:25:35 +000093
jadmanski0afbb632008-06-06 21:10:57 +000094 ## in brief mode we display grid table only and nothing more
95 ## - mouse hovering feature is stubbed in brief mode
96 ## - any link opens new window or tab
mbligh439661b2008-02-19 15:57:53 +000097
jadmanski0afbb632008-06-06 21:10:57 +000098 redirect = ""
99 if is_brief_mode():
100 ## we are acting under AFE
101 ## any link shall open new window
102 redirect = " target=NEW"
103
104 if data:
105 data = "<tt>%s</tt>" % data
106
107 if link and not tooltip:
108 ## FlipAxis corner, column and row headers
109 self.data = ('<a href="%s"%s>%s</a>' %
110 (link, redirect, data))
111 else:
112 self.data = calculate_html(link, data, tooltip,
113 row_label, column_label)
114
115 if color_map.has_key(color_key):
116 self.color = color_map[color_key]
117 elif header:
118 self.color = color_map['header']
119 elif data:
120 self.color = color_map['plain_text']
121 else:
122 self.color = color_map['blank']
123 self.header = header
mblighcfd2d012007-09-19 21:07:34 +0000124
125
jadmanski0afbb632008-06-06 21:10:57 +0000126 def html(self):
127 if self.data:
128 data = self.data
129 else:
130 data = '&nbsp'
mblighcfd2d012007-09-19 21:07:34 +0000131
jadmanski0afbb632008-06-06 21:10:57 +0000132 if self.header:
133 box_html = 'th'
134 else:
135 box_html = 'td'
mblighcfd2d012007-09-19 21:07:34 +0000136
jadmanski0afbb632008-06-06 21:10:57 +0000137 return "<%s bgcolor=%s>%s</%s>" % \
138 (box_html, self.color, data, box_html)
mblighcfd2d012007-09-19 21:07:34 +0000139
140
mbligh439661b2008-02-19 15:57:53 +0000141def grade_from_status(status):
jadmanski0afbb632008-06-06 21:10:57 +0000142 # % of goodness
143 # GOOD (6) -> 1
144 # TEST_NA (8) is not counted
145 # ## If the test doesn't PASS, it FAILS
146 # else -> 0
mbligh439661b2008-02-19 15:57:53 +0000147
jadmanski0afbb632008-06-06 21:10:57 +0000148 if status == 6:
149 return 1.0
150 else:
151 return 0.0
mbligh439661b2008-02-19 15:57:53 +0000152
153
154def average_grade_from_status_count(status_count):
jadmanski0afbb632008-06-06 21:10:57 +0000155 average_grade = 0
156 total_count = 0
157 for key in status_count.keys():
mbligh3845f522008-08-01 14:29:22 +0000158 if key not in (8, 9): # TEST_NA, RUNNING
jadmanski0afbb632008-06-06 21:10:57 +0000159 average_grade += (grade_from_status(key)
160 * status_count[key])
161 total_count += status_count[key]
162 if total_count != 0:
163 average_grade = average_grade / total_count
164 else:
165 average_grade = 0.0
166 return average_grade
mbligh439661b2008-02-19 15:57:53 +0000167
168
169def shade_from_status_count(status_count):
jadmanski0afbb632008-06-06 21:10:57 +0000170 if not status_count:
171 return None
172
173 ## average_grade defines a shade of the box
174 ## 0 -> violet
175 ## 0.76 -> red
176 ## 0.88-> yellow
177 ## 1.0 -> green
178 average_grade = average_grade_from_status_count(status_count)
179
180 ## find appropiate keyword from color_map
181 if average_grade<0.01:
182 shade = '0pct'
183 elif average_grade<0.75:
184 shade = '75pct'
185 elif average_grade<0.85:
186 shade = '85pct'
187 elif average_grade<0.90:
188 shade = '90pct'
189 elif average_grade<0.95:
190 shade = '95pct'
191 else:
192 shade = '100pct'
193
194 return shade
mbligh439661b2008-02-19 15:57:53 +0000195
196
mbligh31260692008-04-16 23:12:12 +0000197def status_html(db, box_data, shade):
jadmanski0afbb632008-06-06 21:10:57 +0000198 """
199 status_count: dict mapping from status (integer key) to count
200 eg. { 'GOOD' : 4, 'FAIL' : 1 }
201 """
mbligh3845f522008-08-01 14:29:22 +0000202 status_count_subset = box_data.status_count.copy()
203 status_count_subset[8] = 0 # Don't count TEST_NA
204 status_count_subset[9] = 0 # Don't count RUNNING
205 html = "%d&nbsp;/&nbsp;%d " % (status_count_subset.get(6, 0),
206 sum(status_count_subset.values()))
207 if 8 in box_data.status_count.keys():
208 html += ' (%d&nbsp;N/A)' % box_data.status_count[8]
209 if 9 in box_data.status_count.keys():
210 html += ' (%d&nbsp;running)' % box_data.status_count[9]
mbligh439661b2008-02-19 15:57:53 +0000211
jadmanski0afbb632008-06-06 21:10:57 +0000212 if box_data.reasons_list:
213 reasons_list = box_data.reasons_list
214 aggregated_reasons_list = \
215 reason_qualifier.aggregate_reason_fields(reasons_list)
216 for reason in aggregated_reasons_list:
217 ## a bit of more postprocessing
218 ## to look nicer in a cell
219 ## in future: to do subtable within the cell
220 reason = reason.replace('<br>','\n')
221 reason = reason.replace('<','[').replace('>',']')
222 reason = reason.replace('|','\n').replace('&',' AND ')
223 reason = reason.replace('\n','<br>')
224 html += '<br>' + reason
mbligh31260692008-04-16 23:12:12 +0000225
jadmanski0afbb632008-06-06 21:10:57 +0000226 tooltip = ""
mbligh3845f522008-08-01 14:29:22 +0000227 for status in sorted(box_data.status_count.keys(), reverse = True):
jadmanski0afbb632008-06-06 21:10:57 +0000228 status_word = db.status_word[status]
mbligh3845f522008-08-01 14:29:22 +0000229 tooltip += "%d %s " % (box_data.status_count[status], status_word)
jadmanski0afbb632008-06-06 21:10:57 +0000230 return (html,tooltip)
mbligha997a342007-10-06 22:35:04 +0000231
232
233def status_count_box(db, tests, link = None):
jadmanski0afbb632008-06-06 21:10:57 +0000234 """
235 Display a ratio of total number of GOOD tests
236 to total number of all tests in the group of tests.
237 More info (e.g. 10 GOOD, 2 WARN, 3 FAIL) is in tooltips
238 """
239 if not tests:
240 return box(None, None)
mbligha997a342007-10-06 22:35:04 +0000241
jadmanski0afbb632008-06-06 21:10:57 +0000242 status_count = {}
243 for test in tests:
244 count = status_count.get(test.status_num, 0)
245 status_count[test.status_num] = count + 1
246 return status_precounted_box(db, status_count, link)
mbligh83f63a02007-12-12 19:13:04 +0000247
248
jadmanskif9fa4272008-05-02 15:43:33 +0000249def status_precounted_box(db, box_data, link = None,
jadmanski0afbb632008-06-06 21:10:57 +0000250 x_label = None, y_label = None):
251 """
252 Display a ratio of total number of GOOD tests
253 to total number of all tests in the group of tests.
254 More info (e.g. 10 GOOD, 2 WARN, 3 FAIL) is in tooltips
255 """
256 status_count = box_data.status_count
257 if not status_count:
258 return box(None, None)
259
260 shade = shade_from_status_count(status_count)
261 html,tooltip = status_html(db, box_data, shade)
262 precounted_box = box(html, shade, False, link, tooltip,
263 x_label, y_label)
264 return precounted_box
mbligha997a342007-10-06 22:35:04 +0000265
mbligh31260692008-04-16 23:12:12 +0000266
mblighcfd2d012007-09-19 21:07:34 +0000267def print_table(matrix):
jadmanski0afbb632008-06-06 21:10:57 +0000268 """
269 matrix: list of lists of boxes, giving a matrix of data
270 Each of the inner lists is a row, not a column.
mblighcfd2d012007-09-19 21:07:34 +0000271
jadmanski0afbb632008-06-06 21:10:57 +0000272 Display the given matrix of data as a table.
273 """
mblighcfd2d012007-09-19 21:07:34 +0000274
jadmanski0afbb632008-06-06 21:10:57 +0000275 print ('<table bgcolor="%s" cellspacing="1" cellpadding="5" '
276 'style="margin-right: 200px;">') % (
277 color_map['borders'])
278 for row in matrix:
279 print '<tr>'
280 for element in row:
281 print element.html()
282 print '</tr>'
283 print '</table>'
mblighcfd2d012007-09-19 21:07:34 +0000284
285
mblighcfd2d012007-09-19 21:07:34 +0000286def sort_tests(tests):
jadmanski0afbb632008-06-06 21:10:57 +0000287 kernel_order = ['patch', 'config', 'build', 'mkinitrd', 'install']
mblighcfd2d012007-09-19 21:07:34 +0000288
jadmanski0afbb632008-06-06 21:10:57 +0000289 results = []
290 for kernel_op in kernel_order:
291 test = 'kernel.' + kernel_op
292 if tests.count(test):
293 results.append(test)
294 tests.remove(test)
295 if tests.count('boot'):
296 results.append('boot')
297 tests.remove('boot')
298 return results + sorted(tests)
mblighbfec5222007-09-14 16:58:57 +0000299
mbligh04598752007-10-01 15:49:58 +0000300
301def print_main_header():
jadmanski0afbb632008-06-06 21:10:57 +0000302 hover_css="""\
jadmanskif9fa4272008-05-02 15:43:33 +0000303a.info{
jadmanski0afbb632008-06-06 21:10:57 +0000304position:relative; /*this is the key*/
305z-index:1
306color:#000;
307text-decoration:none}
jadmanskif9fa4272008-05-02 15:43:33 +0000308
309a.info:hover{z-index:25;}
310
311a.info span{display: none}
312
313a.info:hover span{ /*the span will display just on :hover state*/
jadmanski0afbb632008-06-06 21:10:57 +0000314display:block;
315position:absolute;
316top:1em; left:1em;
317min-width: 100px;
318overflow: visible;
319border:1px solid #036;
320background-color:#fff; color:#000;
321text-align: left
jadmanskif9fa4272008-05-02 15:43:33 +0000322}
323"""
jadmanski0afbb632008-06-06 21:10:57 +0000324 print '<head><style type="text/css">'
325 print 'a { text-decoration: none }'
326 print hover_css
327 print '</style></head>'
328 print '<h2>'
329 print '<a href="compose_query.cgi">Functional</a>'
330 print '&nbsp&nbsp&nbsp'
331 print '<a href="machine_benchmark.cgi">Performance</a>'
332 print '&nbsp&nbsp&nbsp'
mbligh9701f7d2009-01-13 23:16:47 +0000333 print '<a href="http://autotest.kernel.org">[About Page]</a>'
jadmanski0afbb632008-06-06 21:10:57 +0000334 print '</h2><p>'
mbligh7a41a862007-11-30 17:44:24 +0000335
336
337def group_name(group):
jadmanski0afbb632008-06-06 21:10:57 +0000338 name = re.sub('_', '<br>', group.name)
339 if re.search('/', name):
340 (owner, machine) = name.split('/', 1)
341 name = owner + '<br>' + machine
342 return name
mblighc3c8eab2009-01-21 18:50:57 +0000343
344def print_add_test_form(available_params, attributes, cleared):
345 print '<form method="post">'
346 print '<input type="hidden" name="attributes" value="%s" />' % attributes
347 print '<input type="hidden" name="cleared" value="%s" />' % cleared
348 print '<select name="key">'
349 for text in available_params:
350 print '<option value="%s">%s</option>' % (text, text)
351 print '</select>'
352 print '<input type="submit" name="add" value="Add test" />'
353 print '<input type="submit" name="clear" value="Clear all tests" />'
354 print '<input type="submit" name="reset" value="Reset" />'
355 print '</form>'
356