blob: 9033c20a1bb3f2604ecbefac4dc2a686fb354ce4 [file] [log] [blame]
mbligh4a370cf2008-04-01 19:56:05 +00001import os, re, db, sys, datetime
mbligh753362d2009-06-22 18:37:49 +00002import common
3from autotest_lib.client.common_lib import kernel_versions
4
mbligh27eab242008-05-21 18:24:10 +00005MAX_RECORDS = 50000L
6MAX_CELLS = 500000L
mbligh9bb92fe2007-09-12 15:54:23 +00007
mbligh2ba3e732008-01-16 01:30:19 +00008tko = os.path.dirname(os.path.realpath(os.path.abspath(__file__)))
mbligh2aaeb672007-10-01 14:54:18 +00009root_url_file = os.path.join(tko, '.root_url')
10if os.path.exists(root_url_file):
jadmanski0afbb632008-06-06 21:10:57 +000011 html_root = open(root_url_file, 'r').readline().rstrip()
mbligh2aaeb672007-10-01 14:54:18 +000012else:
jadmanski0afbb632008-06-06 21:10:57 +000013 html_root = '/results/'
mbligh2aaeb672007-10-01 14:54:18 +000014
mbligh2e4e5df2007-11-05 17:22:46 +000015
mbligh2ba3e732008-01-16 01:30:19 +000016class status_cell:
jadmanski0afbb632008-06-06 21:10:57 +000017 # One cell in the matrix of status data.
18 def __init__(self):
19 # Count is a dictionary: status -> count of tests with status
20 self.status_count = {}
21 self.reasons_list = []
22 self.job_tag = None
23 self.job_tag_count = 0
mbligh2e4e5df2007-11-05 17:22:46 +000024
mbligh83f63a02007-12-12 19:13:04 +000025
jadmanski0afbb632008-06-06 21:10:57 +000026 def add(self, status, count, job_tags, reasons = None):
27 assert count > 0
mbligh2ba3e732008-01-16 01:30:19 +000028
jadmanski0afbb632008-06-06 21:10:57 +000029 self.job_tag = job_tags
30 self.job_tag_count += count
31 if self.job_tag_count > 1:
32 self.job_tag = None
33
34 self.status_count[status] = count
35 ### status == 6 means 'GOOD'
36 if status != 6:
37 ## None implies sorting problems and extra CRs in a cell
38 if reasons:
39 self.reasons_list.append(reasons)
mbligh2ba3e732008-01-16 01:30:19 +000040
41
42class status_data:
jadmanski0afbb632008-06-06 21:10:57 +000043 def __init__(self, sql_rows, x_field, y_field, query_reasons = False):
44 data = {}
45 y_values = set()
mbligh2ba3e732008-01-16 01:30:19 +000046
jadmanski0afbb632008-06-06 21:10:57 +000047 # Walk through the query, filing all results by x, y info
48 for row in sql_rows:
49 if query_reasons:
50 (x,y, status, count, job_tags, reasons) = row
51 else:
52 (x,y, status, count, job_tags) = row
53 reasons = None
54 if not data.has_key(x):
55 data[x] = {}
56 if not data[x].has_key(y):
57 y_values.add(y)
58 data[x][y] = status_cell()
59 data[x][y].add(status, count, job_tags, reasons)
mbligh2ba3e732008-01-16 01:30:19 +000060
jadmanski0afbb632008-06-06 21:10:57 +000061 # 2-d hash of data - [x-value][y-value]
62 self.data = data
63 # List of possible columns (x-values)
64 self.x_values = smart_sort(data.keys(), x_field)
65 # List of rows columns (y-values)
66 self.y_values = smart_sort(list(y_values), y_field)
67 nCells = len(self.y_values)*len(self.x_values)
68 if nCells > MAX_CELLS:
69 msg = 'Exceeded allowed number of cells in a table'
70 raise db.MySQLTooManyRows(msg)
71
mbligh83f63a02007-12-12 19:13:04 +000072
mbligh31260692008-04-16 23:12:12 +000073def get_matrix_data(db_obj, x_axis, y_axis, where = None,
jadmanski0afbb632008-06-06 21:10:57 +000074 query_reasons = False):
75 # Searches on the test_view table - x_axis and y_axis must both be
76 # column names in that table.
77 x_field = test_view_field_dict[x_axis]
78 y_field = test_view_field_dict[y_axis]
79 query_fields_list = [x_field, y_field, 'status','COUNT(status)']
80 query_fields_list.append("LEFT(GROUP_CONCAT(job_tag),100)")
81 if query_reasons:
82 query_fields_list.append(
83 "LEFT(GROUP_CONCAT(DISTINCT reason SEPARATOR '|'),500)"
84 )
85 fields = ','.join(query_fields_list)
mbligh31260692008-04-16 23:12:12 +000086
jadmanski0afbb632008-06-06 21:10:57 +000087 group_by = '%s, %s, status' % (x_field, y_field)
showardeab66ce2009-12-23 00:03:56 +000088 rows = db_obj.select(fields, 'tko_test_view',
jadmanski0afbb632008-06-06 21:10:57 +000089 where=where, group_by=group_by, max_rows = MAX_RECORDS)
90 return status_data(rows, x_field, y_field, query_reasons)
mbligh83f63a02007-12-12 19:13:04 +000091
92
mbligh2ba3e732008-01-16 01:30:19 +000093# Dictionary used simply for fast lookups from short reference names for users
94# to fieldnames in test_view
95test_view_field_dict = {
jadmanski0afbb632008-06-06 21:10:57 +000096 'kernel' : 'kernel_printable',
97 'hostname' : 'machine_hostname',
98 'test' : 'test',
99 'label' : 'job_label',
100 'machine_group' : 'machine_group',
101 'reason' : 'reason',
102 'tag' : 'job_tag',
103 'user' : 'job_username',
104 'status' : 'status_word',
105 'time' : 'test_finished_time',
mbligh8d88a6d2009-02-05 21:37:12 +0000106 'start_time' : 'test_started_time',
jadmanski0afbb632008-06-06 21:10:57 +0000107 'time_daily' : 'DATE(test_finished_time)'
mbligh2ba3e732008-01-16 01:30:19 +0000108}
mbligh2b672532007-11-05 19:24:51 +0000109
mbligh31260692008-04-16 23:12:12 +0000110
mbligh2ba3e732008-01-16 01:30:19 +0000111def smart_sort(list, field):
jadmanski0afbb632008-06-06 21:10:57 +0000112 if field == 'kernel_printable':
113 def kernel_encode(kernel):
114 return kernel_versions.version_encode(kernel)
115 list.sort(key = kernel_encode, reverse = True)
116 return list
117 ## old records may contain time=None
118 ## make None comparable with timestamp datetime or date
119 elif field == 'test_finished_time':
120 def convert_None_to_datetime(date_time):
121 if not date_time:
122 return datetime.datetime(1970, 1, 1, 0, 0, 0)
123 else:
124 return date_time
125 list = map(convert_None_to_datetime, list)
126 elif field == 'DATE(test_finished_time)':
127 def convert_None_to_date(date):
128 if not date:
129 return datetime.date(1970, 1, 1)
130 else:
131 return date
132 list = map(convert_None_to_date, list)
133 list.sort()
134 return list
mbligh2e4e5df2007-11-05 17:22:46 +0000135
mbligh2aaeb672007-10-01 14:54:18 +0000136
mblighcff2d212007-10-07 00:11:10 +0000137class group:
jadmanski0afbb632008-06-06 21:10:57 +0000138 @classmethod
139 def select(klass, db):
140 """Return all possible machine groups"""
showardeab66ce2009-12-23 00:03:56 +0000141 rows = db.select('distinct machine_group', 'tko_machines',
jadmanski0afbb632008-06-06 21:10:57 +0000142 'machine_group is not null')
143 groupnames = sorted([row[0] for row in rows])
144 return [klass(db, groupname) for groupname in groupnames]
mbligh83f63a02007-12-12 19:13:04 +0000145
146
jadmanski0afbb632008-06-06 21:10:57 +0000147 def __init__(self, db, name):
148 self.name = name
149 self.db = db
mblighcff2d212007-10-07 00:11:10 +0000150
151
jadmanski0afbb632008-06-06 21:10:57 +0000152 def machines(self):
153 return machine.select(self.db, { 'machine_group' : self.name })
mbligh2e4e5df2007-11-05 17:22:46 +0000154
mblighcff2d212007-10-07 00:11:10 +0000155
jadmanski0afbb632008-06-06 21:10:57 +0000156 def tests(self, where = {}):
157 values = [self.name]
showardeab66ce2009-12-23 00:03:56 +0000158 sql = 't inner join tko_machines m on m.machine_idx=t.machine_idx'
jadmanski0afbb632008-06-06 21:10:57 +0000159 sql += ' where m.machine_group=%s'
160 for key in where.keys():
161 sql += ' and %s=%%s' % key
162 values.append(where[key])
163 return test.select_sql(self.db, sql, values)
mblighcff2d212007-10-07 00:11:10 +0000164
mbligh2e4e5df2007-11-05 17:22:46 +0000165
mbligh2aaeb672007-10-01 14:54:18 +0000166class machine:
jadmanski0afbb632008-06-06 21:10:57 +0000167 @classmethod
168 def select(klass, db, where = {}):
169 fields = ['machine_idx', 'hostname', 'machine_group', 'owner']
170 machines = []
showardeab66ce2009-12-23 00:03:56 +0000171 for row in db.select(','.join(fields), 'tko_machines', where):
jadmanski0afbb632008-06-06 21:10:57 +0000172 machines.append(klass(db, *row))
173 return machines
mbligh2aaeb672007-10-01 14:54:18 +0000174
175
jadmanski0afbb632008-06-06 21:10:57 +0000176 def __init__(self, db, idx, hostname, group, owner):
177 self.db = db
178 self.idx = idx
179 self.hostname = hostname
180 self.group = group
181 self.owner = owner
mbligh2e4e5df2007-11-05 17:22:46 +0000182
mbligh250300e2007-09-18 00:50:57 +0000183
mbligh9bb92fe2007-09-12 15:54:23 +0000184class kernel:
jadmanski0afbb632008-06-06 21:10:57 +0000185 @classmethod
186 def select(klass, db, where = {}):
187 fields = ['kernel_idx', 'kernel_hash', 'base', 'printable']
showardeab66ce2009-12-23 00:03:56 +0000188 rows = db.select(','.join(fields), 'tko_kernels', where)
jadmanski0afbb632008-06-06 21:10:57 +0000189 return [klass(db, *row) for row in rows]
mbligh9bb92fe2007-09-12 15:54:23 +0000190
mbligh8e1ab172007-09-13 17:29:56 +0000191
jadmanski0afbb632008-06-06 21:10:57 +0000192 def __init__(self, db, idx, hash, base, printable):
193 self.db = db
194 self.idx = idx
195 self.hash = hash
196 self.base = base
197 self.printable = printable
198 self.patches = [] # THIS SHOULD PULL IN PATCHES!
mbligh9bb92fe2007-09-12 15:54:23 +0000199
200
201class test:
jadmanski0afbb632008-06-06 21:10:57 +0000202 @classmethod
showardc1a98d12010-01-15 00:22:22 +0000203 def select(klass, db, where={}, distinct=False):
jadmanski0afbb632008-06-06 21:10:57 +0000204 fields = ['test_idx', 'job_idx', 'test', 'subdir',
205 'kernel_idx', 'status', 'reason', 'machine_idx']
206 tests = []
showardeab66ce2009-12-23 00:03:56 +0000207 for row in db.select(','.join(fields), 'tko_tests', where,
showardc1a98d12010-01-15 00:22:22 +0000208 distinct):
jadmanski0afbb632008-06-06 21:10:57 +0000209 tests.append(klass(db, *row))
210 return tests
mbligh8e1ab172007-09-13 17:29:56 +0000211
212
jadmanski0afbb632008-06-06 21:10:57 +0000213 @classmethod
214 def select_sql(klass, db, sql, values):
215 fields = ['test_idx', 'job_idx', 'test', 'subdir',
216 'kernel_idx', 'status', 'reason', 'machine_idx']
217 fields = ['t.'+field for field in fields]
showardeab66ce2009-12-23 00:03:56 +0000218 rows = db.select_sql(','.join(fields), 'tko_tests', sql, values)
jadmanski0afbb632008-06-06 21:10:57 +0000219 return [klass(db, *row) for row in rows]
mbligh16ae9262007-09-21 00:53:08 +0000220
mbligh50a25252007-09-27 15:26:17 +0000221
jadmanski0afbb632008-06-06 21:10:57 +0000222 def __init__(self, db, test_idx, job_idx, testname, subdir, kernel_idx,
223 status_num, reason, machine_idx):
224 self.idx = test_idx
225 self.job = job(db, job_idx)
226 self.testname = testname
227 self.subdir = subdir
228 self.kernel_idx = kernel_idx
229 self.__kernel = None
230 self.__iterations = None
231 self.machine_idx = machine_idx
232 self.__machine = None
233 self.status_num = status_num
234 self.status_word = db.status_word[status_num]
235 self.reason = reason
236 self.db = db
237 if self.subdir:
238 self.url = html_root + self.job.tag + '/' + self.subdir
239 else:
240 self.url = None
mbligh50a25252007-09-27 15:26:17 +0000241
mbligh250300e2007-09-18 00:50:57 +0000242
jadmanski0afbb632008-06-06 21:10:57 +0000243 def iterations(self):
244 """
245 Caching function for iterations
246 """
247 if not self.__iterations:
248 self.__iterations = {}
249 # A dictionary - dict{key} = [value1, value2, ....]
250 where = {'test_idx' : self.idx}
251 for i in iteration.select(self.db, where):
252 if self.__iterations.has_key(i.key):
253 self.__iterations[i.key].append(i.value)
254 else:
255 self.__iterations[i.key] = [i.value]
256 return self.__iterations
257
258
259 def kernel(self):
260 """
261 Caching function for kernels
262 """
263 if not self.__kernel:
264 where = {'kernel_idx' : self.kernel_idx}
265 self.__kernel = kernel.select(self.db, where)[0]
266 return self.__kernel
267
268
269 def machine(self):
270 """
271 Caching function for kernels
272 """
273 if not self.__machine:
274 where = {'machine_idx' : self.machine_idx}
275 self.__machine = machine.select(self.db, where)[0]
276 return self.__machine
mbligh2aaeb672007-10-01 14:54:18 +0000277
278
mbligh250300e2007-09-18 00:50:57 +0000279class job:
jadmanski0afbb632008-06-06 21:10:57 +0000280 def __init__(self, db, job_idx):
281 where = {'job_idx' : job_idx}
showardeab66ce2009-12-23 00:03:56 +0000282 rows = db.select('tag, machine_idx', 'tko_jobs', where)
mblighb33e53e2008-06-17 19:41:26 +0000283 if rows:
284 self.tag, self.machine_idx = rows[0]
285 self.job_idx = job_idx
mbligh250300e2007-09-18 00:50:57 +0000286
jadmanski0afbb632008-06-06 21:10:57 +0000287
mbligh16ae9262007-09-21 00:53:08 +0000288class iteration:
jadmanski0afbb632008-06-06 21:10:57 +0000289 @classmethod
290 def select(klass, db, where):
291 fields = ['iteration', 'attribute', 'value']
292 iterations = []
showardeab66ce2009-12-23 00:03:56 +0000293 rows = db.select(','.join(fields), 'tko_iteration_result', where)
jadmanski0afbb632008-06-06 21:10:57 +0000294 for row in rows:
295 iterations.append(klass(*row))
296 return iterations
mbligh16ae9262007-09-21 00:53:08 +0000297
298
jadmanski0afbb632008-06-06 21:10:57 +0000299 def __init__(self, iteration, key, value):
300 self.iteration = iteration
301 self.key = key
302 self.value = value
mbligh16ae9262007-09-21 00:53:08 +0000303
mbligh8e1ab172007-09-13 17:29:56 +0000304# class patch:
jadmanski0afbb632008-06-06 21:10:57 +0000305# def __init__(self):
306# self.spec = None