blob: d9aff027994f17137c51d89095aa7ea0f1e42e0f [file] [log] [blame]
mbligh9bb92fe2007-09-12 15:54:23 +00001#!/usr/bin/python
mbligh4a370cf2008-04-01 19:56:05 +00002import os, re, db, sys, datetime
mbligh753362d2009-06-22 18:37:49 +00003import common
4from autotest_lib.client.common_lib import kernel_versions
5
mbligh27eab242008-05-21 18:24:10 +00006MAX_RECORDS = 50000L
7MAX_CELLS = 500000L
mbligh9bb92fe2007-09-12 15:54:23 +00008
mbligh2ba3e732008-01-16 01:30:19 +00009tko = os.path.dirname(os.path.realpath(os.path.abspath(__file__)))
mbligh2aaeb672007-10-01 14:54:18 +000010root_url_file = os.path.join(tko, '.root_url')
11if os.path.exists(root_url_file):
jadmanski0afbb632008-06-06 21:10:57 +000012 html_root = open(root_url_file, 'r').readline().rstrip()
mbligh2aaeb672007-10-01 14:54:18 +000013else:
jadmanski0afbb632008-06-06 21:10:57 +000014 html_root = '/results/'
mbligh2aaeb672007-10-01 14:54:18 +000015
mbligh2e4e5df2007-11-05 17:22:46 +000016
mbligh2ba3e732008-01-16 01:30:19 +000017class status_cell:
jadmanski0afbb632008-06-06 21:10:57 +000018 # One cell in the matrix of status data.
19 def __init__(self):
20 # Count is a dictionary: status -> count of tests with status
21 self.status_count = {}
22 self.reasons_list = []
23 self.job_tag = None
24 self.job_tag_count = 0
mbligh2e4e5df2007-11-05 17:22:46 +000025
mbligh83f63a02007-12-12 19:13:04 +000026
jadmanski0afbb632008-06-06 21:10:57 +000027 def add(self, status, count, job_tags, reasons = None):
28 assert count > 0
mbligh2ba3e732008-01-16 01:30:19 +000029
jadmanski0afbb632008-06-06 21:10:57 +000030 self.job_tag = job_tags
31 self.job_tag_count += count
32 if self.job_tag_count > 1:
33 self.job_tag = None
34
35 self.status_count[status] = count
36 ### status == 6 means 'GOOD'
37 if status != 6:
38 ## None implies sorting problems and extra CRs in a cell
39 if reasons:
40 self.reasons_list.append(reasons)
mbligh2ba3e732008-01-16 01:30:19 +000041
42
43class status_data:
jadmanski0afbb632008-06-06 21:10:57 +000044 def __init__(self, sql_rows, x_field, y_field, query_reasons = False):
45 data = {}
46 y_values = set()
mbligh2ba3e732008-01-16 01:30:19 +000047
jadmanski0afbb632008-06-06 21:10:57 +000048 # Walk through the query, filing all results by x, y info
49 for row in sql_rows:
50 if query_reasons:
51 (x,y, status, count, job_tags, reasons) = row
52 else:
53 (x,y, status, count, job_tags) = row
54 reasons = None
55 if not data.has_key(x):
56 data[x] = {}
57 if not data[x].has_key(y):
58 y_values.add(y)
59 data[x][y] = status_cell()
60 data[x][y].add(status, count, job_tags, reasons)
mbligh2ba3e732008-01-16 01:30:19 +000061
jadmanski0afbb632008-06-06 21:10:57 +000062 # 2-d hash of data - [x-value][y-value]
63 self.data = data
64 # List of possible columns (x-values)
65 self.x_values = smart_sort(data.keys(), x_field)
66 # List of rows columns (y-values)
67 self.y_values = smart_sort(list(y_values), y_field)
68 nCells = len(self.y_values)*len(self.x_values)
69 if nCells > MAX_CELLS:
70 msg = 'Exceeded allowed number of cells in a table'
71 raise db.MySQLTooManyRows(msg)
72
mbligh83f63a02007-12-12 19:13:04 +000073
mbligh31260692008-04-16 23:12:12 +000074def get_matrix_data(db_obj, x_axis, y_axis, where = None,
jadmanski0afbb632008-06-06 21:10:57 +000075 query_reasons = False):
76 # Searches on the test_view table - x_axis and y_axis must both be
77 # column names in that table.
78 x_field = test_view_field_dict[x_axis]
79 y_field = test_view_field_dict[y_axis]
80 query_fields_list = [x_field, y_field, 'status','COUNT(status)']
81 query_fields_list.append("LEFT(GROUP_CONCAT(job_tag),100)")
82 if query_reasons:
83 query_fields_list.append(
84 "LEFT(GROUP_CONCAT(DISTINCT reason SEPARATOR '|'),500)"
85 )
86 fields = ','.join(query_fields_list)
mbligh31260692008-04-16 23:12:12 +000087
jadmanski0afbb632008-06-06 21:10:57 +000088 group_by = '%s, %s, status' % (x_field, y_field)
89 rows = db_obj.select(fields, 'test_view',
90 where=where, group_by=group_by, max_rows = MAX_RECORDS)
91 return status_data(rows, x_field, y_field, query_reasons)
mbligh83f63a02007-12-12 19:13:04 +000092
93
mbligh2ba3e732008-01-16 01:30:19 +000094# Dictionary used simply for fast lookups from short reference names for users
95# to fieldnames in test_view
96test_view_field_dict = {
jadmanski0afbb632008-06-06 21:10:57 +000097 'kernel' : 'kernel_printable',
98 'hostname' : 'machine_hostname',
99 'test' : 'test',
100 'label' : 'job_label',
101 'machine_group' : 'machine_group',
102 'reason' : 'reason',
103 'tag' : 'job_tag',
104 'user' : 'job_username',
105 'status' : 'status_word',
106 'time' : 'test_finished_time',
mbligh8d88a6d2009-02-05 21:37:12 +0000107 'start_time' : 'test_started_time',
jadmanski0afbb632008-06-06 21:10:57 +0000108 'time_daily' : 'DATE(test_finished_time)'
mbligh2ba3e732008-01-16 01:30:19 +0000109}
mbligh2b672532007-11-05 19:24:51 +0000110
mbligh31260692008-04-16 23:12:12 +0000111
mbligh2ba3e732008-01-16 01:30:19 +0000112def smart_sort(list, field):
jadmanski0afbb632008-06-06 21:10:57 +0000113 if field == 'kernel_printable':
114 def kernel_encode(kernel):
115 return kernel_versions.version_encode(kernel)
116 list.sort(key = kernel_encode, reverse = True)
117 return list
118 ## old records may contain time=None
119 ## make None comparable with timestamp datetime or date
120 elif field == 'test_finished_time':
121 def convert_None_to_datetime(date_time):
122 if not date_time:
123 return datetime.datetime(1970, 1, 1, 0, 0, 0)
124 else:
125 return date_time
126 list = map(convert_None_to_datetime, list)
127 elif field == 'DATE(test_finished_time)':
128 def convert_None_to_date(date):
129 if not date:
130 return datetime.date(1970, 1, 1)
131 else:
132 return date
133 list = map(convert_None_to_date, list)
134 list.sort()
135 return list
mbligh2e4e5df2007-11-05 17:22:46 +0000136
mbligh2aaeb672007-10-01 14:54:18 +0000137
mblighcff2d212007-10-07 00:11:10 +0000138class group:
jadmanski0afbb632008-06-06 21:10:57 +0000139 @classmethod
140 def select(klass, db):
141 """Return all possible machine groups"""
142 rows = db.select('distinct machine_group', 'machines',
143 'machine_group is not null')
144 groupnames = sorted([row[0] for row in rows])
145 return [klass(db, groupname) for groupname in groupnames]
mbligh83f63a02007-12-12 19:13:04 +0000146
147
jadmanski0afbb632008-06-06 21:10:57 +0000148 def __init__(self, db, name):
149 self.name = name
150 self.db = db
mblighcff2d212007-10-07 00:11:10 +0000151
152
jadmanski0afbb632008-06-06 21:10:57 +0000153 def machines(self):
154 return machine.select(self.db, { 'machine_group' : self.name })
mbligh2e4e5df2007-11-05 17:22:46 +0000155
mblighcff2d212007-10-07 00:11:10 +0000156
jadmanski0afbb632008-06-06 21:10:57 +0000157 def tests(self, where = {}):
158 values = [self.name]
159 sql = 't inner join machines m on m.machine_idx=t.machine_idx'
160 sql += ' where m.machine_group=%s'
161 for key in where.keys():
162 sql += ' and %s=%%s' % key
163 values.append(where[key])
164 return test.select_sql(self.db, sql, values)
mblighcff2d212007-10-07 00:11:10 +0000165
mbligh2e4e5df2007-11-05 17:22:46 +0000166
mbligh2aaeb672007-10-01 14:54:18 +0000167class machine:
jadmanski0afbb632008-06-06 21:10:57 +0000168 @classmethod
169 def select(klass, db, where = {}):
170 fields = ['machine_idx', 'hostname', 'machine_group', 'owner']
171 machines = []
172 for row in db.select(','.join(fields), 'machines', where):
173 machines.append(klass(db, *row))
174 return machines
mbligh2aaeb672007-10-01 14:54:18 +0000175
176
jadmanski0afbb632008-06-06 21:10:57 +0000177 def __init__(self, db, idx, hostname, group, owner):
178 self.db = db
179 self.idx = idx
180 self.hostname = hostname
181 self.group = group
182 self.owner = owner
mbligh2e4e5df2007-11-05 17:22:46 +0000183
mbligh250300e2007-09-18 00:50:57 +0000184
mbligh9bb92fe2007-09-12 15:54:23 +0000185class kernel:
jadmanski0afbb632008-06-06 21:10:57 +0000186 @classmethod
187 def select(klass, db, where = {}):
188 fields = ['kernel_idx', 'kernel_hash', 'base', 'printable']
189 rows = db.select(','.join(fields), 'kernels', where)
190 return [klass(db, *row) for row in rows]
mbligh9bb92fe2007-09-12 15:54:23 +0000191
mbligh8e1ab172007-09-13 17:29:56 +0000192
jadmanski0afbb632008-06-06 21:10:57 +0000193 def __init__(self, db, idx, hash, base, printable):
194 self.db = db
195 self.idx = idx
196 self.hash = hash
197 self.base = base
198 self.printable = printable
199 self.patches = [] # THIS SHOULD PULL IN PATCHES!
mbligh9bb92fe2007-09-12 15:54:23 +0000200
201
202class test:
jadmanski0afbb632008-06-06 21:10:57 +0000203 @classmethod
204 def select(klass, db, where = {}, wherein = {}, distinct = False):
205 fields = ['test_idx', 'job_idx', 'test', 'subdir',
206 'kernel_idx', 'status', 'reason', 'machine_idx']
207 tests = []
208 for row in db.select(','.join(fields), 'tests', where,
209 wherein,distinct):
210 tests.append(klass(db, *row))
211 return tests
mbligh8e1ab172007-09-13 17:29:56 +0000212
213
jadmanski0afbb632008-06-06 21:10:57 +0000214 @classmethod
215 def select_sql(klass, db, sql, values):
216 fields = ['test_idx', 'job_idx', 'test', 'subdir',
217 'kernel_idx', 'status', 'reason', 'machine_idx']
218 fields = ['t.'+field for field in fields]
219 rows = db.select_sql(','.join(fields), 'tests', sql, values)
220 return [klass(db, *row) for row in rows]
mbligh16ae9262007-09-21 00:53:08 +0000221
mbligh50a25252007-09-27 15:26:17 +0000222
jadmanski0afbb632008-06-06 21:10:57 +0000223 def __init__(self, db, test_idx, job_idx, testname, subdir, kernel_idx,
224 status_num, reason, machine_idx):
225 self.idx = test_idx
226 self.job = job(db, job_idx)
227 self.testname = testname
228 self.subdir = subdir
229 self.kernel_idx = kernel_idx
230 self.__kernel = None
231 self.__iterations = None
232 self.machine_idx = machine_idx
233 self.__machine = None
234 self.status_num = status_num
235 self.status_word = db.status_word[status_num]
236 self.reason = reason
237 self.db = db
238 if self.subdir:
239 self.url = html_root + self.job.tag + '/' + self.subdir
240 else:
241 self.url = None
mbligh50a25252007-09-27 15:26:17 +0000242
mbligh250300e2007-09-18 00:50:57 +0000243
jadmanski0afbb632008-06-06 21:10:57 +0000244 def iterations(self):
245 """
246 Caching function for iterations
247 """
248 if not self.__iterations:
249 self.__iterations = {}
250 # A dictionary - dict{key} = [value1, value2, ....]
251 where = {'test_idx' : self.idx}
252 for i in iteration.select(self.db, where):
253 if self.__iterations.has_key(i.key):
254 self.__iterations[i.key].append(i.value)
255 else:
256 self.__iterations[i.key] = [i.value]
257 return self.__iterations
258
259
260 def kernel(self):
261 """
262 Caching function for kernels
263 """
264 if not self.__kernel:
265 where = {'kernel_idx' : self.kernel_idx}
266 self.__kernel = kernel.select(self.db, where)[0]
267 return self.__kernel
268
269
270 def machine(self):
271 """
272 Caching function for kernels
273 """
274 if not self.__machine:
275 where = {'machine_idx' : self.machine_idx}
276 self.__machine = machine.select(self.db, where)[0]
277 return self.__machine
mbligh2aaeb672007-10-01 14:54:18 +0000278
279
mbligh250300e2007-09-18 00:50:57 +0000280class job:
jadmanski0afbb632008-06-06 21:10:57 +0000281 def __init__(self, db, job_idx):
282 where = {'job_idx' : job_idx}
283 rows = db.select('tag, machine_idx', 'jobs', where)
mblighb33e53e2008-06-17 19:41:26 +0000284 if rows:
285 self.tag, self.machine_idx = rows[0]
286 self.job_idx = job_idx
mbligh250300e2007-09-18 00:50:57 +0000287
jadmanski0afbb632008-06-06 21:10:57 +0000288
mbligh16ae9262007-09-21 00:53:08 +0000289class iteration:
jadmanski0afbb632008-06-06 21:10:57 +0000290 @classmethod
291 def select(klass, db, where):
292 fields = ['iteration', 'attribute', 'value']
293 iterations = []
294 rows = db.select(','.join(fields), 'iteration_result', where)
295 for row in rows:
296 iterations.append(klass(*row))
297 return iterations
mbligh16ae9262007-09-21 00:53:08 +0000298
299
jadmanski0afbb632008-06-06 21:10:57 +0000300 def __init__(self, iteration, key, value):
301 self.iteration = iteration
302 self.key = key
303 self.value = value
mbligh16ae9262007-09-21 00:53:08 +0000304
mbligh8e1ab172007-09-13 17:29:56 +0000305# class patch:
jadmanski0afbb632008-06-06 21:10:57 +0000306# def __init__(self):
307# self.spec = None