blob: 046d8ffabcf0b56c0a08751069e6a7d66b1f2d50 [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
mblighaea09602008-04-16 22:59:37 +00003MAX_RECORDS = 10000
4MAX_CELLS = 100000
mbligh9bb92fe2007-09-12 15:54:23 +00005
mbligh2ba3e732008-01-16 01:30:19 +00006tko = os.path.dirname(os.path.realpath(os.path.abspath(__file__)))
7client_bin = os.path.abspath(os.path.join(tko, '../client/bin'))
8sys.path.insert(0, client_bin)
9import kernel_versions
10
mbligh2aaeb672007-10-01 14:54:18 +000011root_url_file = os.path.join(tko, '.root_url')
12if os.path.exists(root_url_file):
mbligh4a370cf2008-04-01 19:56:05 +000013 html_root = open(root_url_file, 'r').readline().rstrip()
mbligh2aaeb672007-10-01 14:54:18 +000014else:
mbligh4a370cf2008-04-01 19:56:05 +000015 html_root = '/results/'
mbligh2aaeb672007-10-01 14:54:18 +000016
mbligh2e4e5df2007-11-05 17:22:46 +000017
mbligh2ba3e732008-01-16 01:30:19 +000018class status_cell:
19 # One cell in the matrix of status data.
20 def __init__(self):
21 # Count is a dictionary: status -> count of tests with status
22 self.status_count = {}
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
mbligh2ba3e732008-01-16 01:30:19 +000027 def add(self, status, count, job_tags):
mbligh2ba3e732008-01-16 01:30:19 +000028 assert count > 0
29
30 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
37
38class status_data:
39 def __init__(self, sql_rows, x_field, y_field):
40 data = {}
41 y_values = set()
42
43 # Walk through the query, filing all results by x, y info
44 for (x, y, status, count, job_tags) in sql_rows:
45 if not data.has_key(x):
46 data[x] = {}
47 if not data[x].has_key(y):
48 y_values.add(y)
49 data[x][y] = status_cell()
50 data[x][y].add(status, count, job_tags)
51
52 # 2-d hash of data - [x-value][y-value]
53 self.data = data
54 # List of possible columns (x-values)
55 self.x_values = smart_sort(data.keys(), x_field)
56 # List of rows columns (y-values)
57 self.y_values = smart_sort(list(y_values), y_field)
mblighaea09602008-04-16 22:59:37 +000058 if len(self.y_values)*len(self.x_values) > MAX_CELLS:
59 msg = 'Exceeded allowed number of cells in a table'
60 raise db.MySQLTooManyRows(msg)
61
mbligh83f63a02007-12-12 19:13:04 +000062
mbligh4a370cf2008-04-01 19:56:05 +000063def truncateTimeFieldsInAllRecords(rows, pos):
64 ## reduces hours:min:sec to 00:00:00 in time stamps
65 ## in each record i.e. in each element of "rows"
66 ## Argument pos is equal to position of x-field or y-field
67 ## depending in which field we are going to make such truncation
68 def truncateTimeFieldInOneRecord(row):
69 altRow = list(row)
70 if altRow[pos]!=None:
71 altRow[pos] = datetime.datetime(
72 altRow[pos].year,
73 altRow[pos].month,
74 altRow[pos].day
75 )
76 return tuple(altRow)
77 return map(truncateTimeFieldInOneRecord, rows)
78
mblighaea09602008-04-16 22:59:37 +000079def get_matrix_data(db_obj, x_axis, y_axis, where = None):
mbligh83f63a02007-12-12 19:13:04 +000080 # Searches on the test_view table - x_axis and y_axis must both be
81 # column names in that table.
mbligh2ba3e732008-01-16 01:30:19 +000082 x_field = test_view_field_dict[x_axis]
83 y_field = test_view_field_dict[y_axis]
mbligh4a370cf2008-04-01 19:56:05 +000084 fields = ( '%s, %s, status, COUNT(status), ' +
mbligh2ba3e732008-01-16 01:30:19 +000085 'LEFT(GROUP_CONCAT(job_tag), 100)' # limit what's returned
86 ) % (x_field, y_field)
87 group_by = '%s, %s, status' % (x_field, y_field)
mblighaea09602008-04-16 22:59:37 +000088 rows = db_obj.select(fields, 'test_view',
89 where=where, group_by=group_by, max_rows = MAX_RECORDS)
mbligh4a370cf2008-04-01 19:56:05 +000090 if x_field.endswith("time"):
91 rows = truncateTimeFieldsInAllRecords(rows, 0)
92 if y_field.endswith("time"):
93 rows = truncateTimeFieldsInAllRecords(rows, 1)
mbligh2ba3e732008-01-16 01:30:19 +000094 return status_data(rows, x_field, y_field)
mbligh83f63a02007-12-12 19:13:04 +000095
96
mbligh2ba3e732008-01-16 01:30:19 +000097# Dictionary used simply for fast lookups from short reference names for users
98# to fieldnames in test_view
99test_view_field_dict = {
100 'kernel' : 'kernel_printable',
101 'hostname' : 'machine_hostname',
102 'test' : 'test',
103 'label' : 'job_label',
104 'machine_group' : 'machine_group',
105 'reason' : 'reason',
106 'tag' : 'job_tag',
107 'user' : 'job_username',
108 'status' : 'status_word',
mbligh4a370cf2008-04-01 19:56:05 +0000109 'time' : 'test_finished_time',
110 'time_daily' : 'test_finished_time',
111 'id' : 'test_idx',
mbligh2ba3e732008-01-16 01:30:19 +0000112}
mbligh2b672532007-11-05 19:24:51 +0000113
mbligh2ba3e732008-01-16 01:30:19 +0000114def smart_sort(list, field):
115 if field == 'kernel_printable':
116 def kernel_encode(kernel):
117 return kernel_versions.version_encode(kernel)
118 list.sort(key = kernel_encode, reverse = True)
mbligh4a370cf2008-04-01 19:56:05 +0000119 elif field.endswith('time'):
120 ## old records may contain time=None
121 ## make None comparable with timestamp as string
122 def handleNone(date_time):
123 if date_time==None:
124 return datetime.datetime(1970,1,1,0,0,0)
125 else:
126 return date_time
127 list = map(handleNone,list)
128 list.sort()
mbligh2ba3e732008-01-16 01:30:19 +0000129 return list
mbligh2e4e5df2007-11-05 17:22:46 +0000130
mbligh2aaeb672007-10-01 14:54:18 +0000131
mblighcff2d212007-10-07 00:11:10 +0000132class group:
133 @classmethod
134 def select(klass, db):
135 """Return all possible machine groups"""
136 rows = db.select('distinct machine_group', 'machines',
137 'machine_group is not null')
138 groupnames = sorted([row[0] for row in rows])
139 return [klass(db, groupname) for groupname in groupnames]
mbligh83f63a02007-12-12 19:13:04 +0000140
141
mblighcff2d212007-10-07 00:11:10 +0000142 def __init__(self, db, name):
143 self.name = name
144 self.db = db
145
146
147 def machines(self):
148 return machine.select(self.db, { 'machine_group' : self.name })
mbligh2e4e5df2007-11-05 17:22:46 +0000149
mblighcff2d212007-10-07 00:11:10 +0000150
151 def tests(self, where = {}):
152 values = [self.name]
153 sql = 't inner join machines m on m.machine_idx=t.machine_idx where m.machine_group=%s'
154 for key in where.keys():
155 sql += ' and %s=%%s' % key
156 values.append(where[key])
157 return test.select_sql(self.db, sql, values)
158
mbligh2e4e5df2007-11-05 17:22:46 +0000159
mbligh2aaeb672007-10-01 14:54:18 +0000160class machine:
161 @classmethod
162 def select(klass, db, where = {}):
163 fields = ['machine_idx', 'hostname', 'machine_group', 'owner']
164 machines = []
165 for row in db.select(','.join(fields), 'machines', where):
166 machines.append(klass(db, *row))
167 return machines
168
169
170 def __init__(self, db, idx, hostname, group, owner):
171 self.db = db
172 self.idx = idx
173 self.hostname = hostname
174 self.group = group
mblighf736b332007-12-18 20:56:51 +0000175 self.owner = owner
mbligh2e4e5df2007-11-05 17:22:46 +0000176
mbligh250300e2007-09-18 00:50:57 +0000177
mbligh9bb92fe2007-09-12 15:54:23 +0000178class kernel:
mbligh8e1ab172007-09-13 17:29:56 +0000179 @classmethod
180 def select(klass, db, where = {}):
181 fields = ['kernel_idx', 'kernel_hash', 'base', 'printable']
mbligh83f63a02007-12-12 19:13:04 +0000182 rows = db.select(','.join(fields), 'kernels', where)
183 return [klass(db, *row) for row in rows]
mbligh9bb92fe2007-09-12 15:54:23 +0000184
mbligh8e1ab172007-09-13 17:29:56 +0000185
186 def __init__(self, db, idx, hash, base, printable):
mbligh9bb92fe2007-09-12 15:54:23 +0000187 self.db = db
mbligh8e1ab172007-09-13 17:29:56 +0000188 self.idx = idx
mbligh9bb92fe2007-09-12 15:54:23 +0000189 self.hash = hash
mbligh8e1ab172007-09-13 17:29:56 +0000190 self.base = base
191 self.printable = printable
192 self.patches = [] # THIS SHOULD PULL IN PATCHES!
mbligh9bb92fe2007-09-12 15:54:23 +0000193
194
195class test:
mbligh8e1ab172007-09-13 17:29:56 +0000196 @classmethod
mbligh85952b42007-12-07 16:28:33 +0000197 def select(klass, db, where = {}, wherein = {}, distinct = False):
mbligh8e1ab172007-09-13 17:29:56 +0000198 fields = ['test_idx', 'job_idx', 'test', 'subdir',
mbligh2aaeb672007-10-01 14:54:18 +0000199 'kernel_idx', 'status', 'reason', 'machine_idx']
mbligh8e1ab172007-09-13 17:29:56 +0000200 tests = []
mbligh85952b42007-12-07 16:28:33 +0000201 for row in db.select(','.join(fields), 'tests', where, wherein,distinct):
mbligh8e1ab172007-09-13 17:29:56 +0000202 tests.append(klass(db, *row))
203 return tests
204
205
mbligh414c69e2007-10-05 15:13:06 +0000206 @classmethod
207 def select_sql(klass, db, sql, values):
208 fields = ['test_idx', 'job_idx', 'test', 'subdir',
209 'kernel_idx', 'status', 'reason', 'machine_idx']
210 fields = ['t.'+field for field in fields]
211 rows = db.select_sql(','.join(fields), 'tests', sql, values)
212 return [klass(db, *row) for row in rows]
213
214
mbligh2aaeb672007-10-01 14:54:18 +0000215 def __init__(self, db, test_idx, job_idx, testname, subdir, kernel_idx, status_num, reason, machine_idx):
mbligh8e1ab172007-09-13 17:29:56 +0000216 self.idx = test_idx
mbligh250300e2007-09-18 00:50:57 +0000217 self.job = job(db, job_idx)
mblighde7335d2007-09-26 16:53:20 +0000218 self.testname = testname
mbligh8e1ab172007-09-13 17:29:56 +0000219 self.subdir = subdir
mbligh50a25252007-09-27 15:26:17 +0000220 self.kernel_idx = kernel_idx
221 self.__kernel = None
222 self.__iterations = None
mbligh2aaeb672007-10-01 14:54:18 +0000223 self.machine_idx = machine_idx
224 self.__machine = None
mbligh8e1ab172007-09-13 17:29:56 +0000225 self.status_num = status_num
226 self.status_word = db.status_word[status_num]
mbligh9bb92fe2007-09-12 15:54:23 +0000227 self.reason = reason
mbligh50a25252007-09-27 15:26:17 +0000228 self.db = db
mblighde7335d2007-09-26 16:53:20 +0000229 if self.subdir:
230 self.url = html_root + self.job.tag + '/' + self.subdir
231 else:
mbligh676510c2007-09-28 01:28:12 +0000232 self.url = None
mbligh16ae9262007-09-21 00:53:08 +0000233
mbligh50a25252007-09-27 15:26:17 +0000234
mbligh50a25252007-09-27 15:26:17 +0000235 def iterations(self):
236 """
237 Caching function for iterations
238 """
239 if not self.__iterations:
240 self.__iterations = {}
241 # A dictionary - dict{key} = [value1, value2, ....]
242 where = {'test_idx' : self.idx}
243 for i in iteration.select(self.db, where):
244 if self.__iterations.has_key(i.key):
245 self.__iterations[i.key].append(i.value)
246 else:
247 self.__iterations[i.key] = [i.value]
248 return self.__iterations
249
250
251 def kernel(self):
252 """
253 Caching function for kernels
254 """
255 if not self.__kernel:
256 where = {'kernel_idx' : self.kernel_idx}
257 self.__kernel = kernel.select(self.db, where)[0]
258 return self.__kernel
259
mbligh250300e2007-09-18 00:50:57 +0000260
mbligh2aaeb672007-10-01 14:54:18 +0000261 def machine(self):
262 """
263 Caching function for kernels
264 """
265 if not self.__machine:
266 where = {'machine_idx' : self.machine_idx}
267 self.__machine = machine.select(self.db, where)[0]
268 return self.__machine
269
270
mbligh250300e2007-09-18 00:50:57 +0000271class job:
272 def __init__(self, db, job_idx):
273 where = {'job_idx' : job_idx}
mbligh2aaeb672007-10-01 14:54:18 +0000274 rows = db.select('tag, machine_idx', 'jobs', where)
mbligh250300e2007-09-18 00:50:57 +0000275 if not rows:
276 return None
mbligh2aaeb672007-10-01 14:54:18 +0000277 (self.tag, self.machine_idx) = rows[0]
mbligh2b672532007-11-05 19:24:51 +0000278 self.job_idx = job_idx
mbligh250300e2007-09-18 00:50:57 +0000279
mbligh8e1ab172007-09-13 17:29:56 +0000280
mbligh16ae9262007-09-21 00:53:08 +0000281class iteration:
282 @classmethod
283 def select(klass, db, where):
284 fields = ['iteration', 'attribute', 'value']
285 iterations = []
286 rows = db.select(','.join(fields), 'iteration_result', where)
287 for row in rows:
288 iterations.append(klass(*row))
289 return iterations
290
291
292 def __init__(self, iteration, key, value):
mbligh4a370cf2008-04-01 19:56:05 +0000293 self.iteration = iteration
mbligh16ae9262007-09-21 00:53:08 +0000294 self.key = key
295 self.value = value
296
mbligh8e1ab172007-09-13 17:29:56 +0000297# class patch:
298# def __init__(self):
299# self.spec = None