Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: client/bin/factory.py

Issue 3151032: Add unique_name test attr, fix UI active test selection, clean up test_list. (Closed) Base URL: http://src.chromium.org/git/autotest.git
Patch Set: sequences get unique_name too Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | client/bin/factory_ui » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 5
6 # DESCRIPTION : 6 # DESCRIPTION :
7 # 7 #
8 # This library provides common types and routines for the factory ui 8 # This library provides common types and routines for the factory ui
9 # infrastructure. This library explicitly does not import gtk, to 9 # infrastructure. This library explicitly does not import gtk, to
10 # allow its use by the autotest control process. 10 # allow its use by the autotest control process.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
44 if l != 'self'] 44 if l != 'self']
45 c = ('%s' % self.__class__).rpartition('.')[2] 45 c = ('%s' % self.__class__).rpartition('.')[2]
46 return '%s(%s)' % (c, ','.join(d)) 46 return '%s(%s)' % (c, ','.join(d))
47 47
48 class FactoryAutotestTest(FactoryTest): 48 class FactoryAutotestTest(FactoryTest):
49 # Placeholder parent for tests with autotest_name fields. 49 # Placeholder parent for tests with autotest_name fields.
50 pass 50 pass
51 51
52 class OperatorTest(FactoryAutotestTest): 52 class OperatorTest(FactoryAutotestTest):
53 def __init__(self, label_en='', label_zw='', autotest_name=None, 53 def __init__(self, label_en='', label_zw='', autotest_name=None,
54 kbd_shortcut=None, dargs={}, drop_caches=False): 54 kbd_shortcut=None, dargs={}, drop_caches=False,
55 unique_name=None):
55 self.__dict__.update(vars()) 56 self.__dict__.update(vars())
56 57
57 class InformationScreen(OperatorTest): 58 class InformationScreen(OperatorTest):
58 # These tests never pass or fail, just return to untested state. 59 # These tests never pass or fail, just return to untested state.
59 pass 60 pass
60 61
61 class AutomatedSequence(FactoryTest): 62 class AutomatedSequence(FactoryTest):
62 def __init__(self, label_en='', label_zw='', subtest_tag_prefix=None, 63 def __init__(self, label_en='', label_zw='', subtest_tag_prefix=None,
63 kbd_shortcut=None, subtest_list=[]): 64 kbd_shortcut=None, subtest_list=[], unique_name=None):
64 self.__dict__.update(vars()) 65 self.__dict__.update(vars())
65 66
66 class AutomatedSubTest(FactoryAutotestTest): 67 class AutomatedSubTest(FactoryAutotestTest):
67 def __init__(self, label_en='', label_zw='', autotest_name=None, 68 def __init__(self, label_en='', label_zw='', autotest_name=None,
68 dargs={}, drop_caches=False): 69 dargs={}, drop_caches=False, unique_name=None):
69 self.__dict__.update(vars()) 70 self.__dict__.update(vars())
70 71
71 class AutomatedRebootSubTest(FactoryAutotestTest): 72 class AutomatedRebootSubTest(FactoryAutotestTest):
72 def __init__(self, label_en='', label_zw='', iterations=None, 73 def __init__(self, label_en='', label_zw='', iterations=None,
73 autotest_name='factory_RebootStub', dargs={}, 74 autotest_name='factory_RebootStub', dargs={},
74 drop_caches=False): 75 drop_caches=False, unique_name=None):
75 self.__dict__.update(vars()) 76 self.__dict__.update(vars())
76 77
77 78
78 class TestDatabase: 79 class TestDatabase:
79 80
80 def __init__(self, test_list): 81 def __init__(self, test_list):
81 self.test_queue = [t for t in reversed(test_list)] 82 self.test_queue = [t for t in reversed(test_list)]
82 self._subtest_parent_map = {} 83 self._subtest_parent_map = {}
83 self._tag_prefix_map = {} 84 self._tag_prefix_map = {}
84 for test in test_list: 85 for test in test_list:
85 if not isinstance(test, AutomatedSequence): 86 if not isinstance(test, AutomatedSequence):
86 self._tag_prefix_map[test] = test.kbd_shortcut 87 self._tag_prefix_map[test] = test.kbd_shortcut
87 continue 88 continue
88 step_count = 1 89 step_count = 1
89 for subtest in test.subtest_list: 90 for subtest in test.subtest_list:
90 self._subtest_parent_map[subtest] = test 91 self._subtest_parent_map[subtest] = test
91 if not isinstance(subtest, FactoryAutotestTest): 92 if not isinstance(subtest, FactoryAutotestTest):
92 continue 93 continue
93 tag_prefix = ('%s_s%d' % (test.subtest_tag_prefix, step_count)) 94 tag_prefix = ('%s_s%d' % (test.subtest_tag_prefix, step_count))
94 self._tag_prefix_map[subtest] = tag_prefix 95 self._tag_prefix_map[subtest] = tag_prefix
95 step_count += 1 96 step_count += 1
96 self.seq_test_set = set(test for test in test_list 97 self.seq_test_set = set(test for test in test_list
97 if isinstance(test, AutomatedSequence)) 98 if isinstance(test, AutomatedSequence))
98 self.subtest_set = set(reduce(lambda x, y: x + y, 99 self.subtest_set = set(reduce(lambda x, y: x + y,
99 [test.subtest_list for test in 100 [test.subtest_list for test in
100 self.seq_test_set], [])) 101 self.seq_test_set], []))
101 self._subtest_map = dict((self._tag_prefix_map[st], st) 102 self._subtest_map = dict((self._tag_prefix_map[st], st)
102 for st in self.subtest_set) 103 for st in self.subtest_set)
103 self._unique_name_map = dict((self.get_unique_name(t), t) 104 self.all_tests = set(test_list) | self.subtest_set
104 for t in self._tag_prefix_map) 105 self._unique_name_map = dict((t.unique_name, t) for t in self.all_tests
106 if isinstance(t, FactoryAutotestTest)
107 and t.unique_name is not None)
108 self._unique_details_map = dict((self.get_unique_details(t), t)
109 for t in self.all_tests)
105 self._kbd_shortcut_map = dict((test.kbd_shortcut, test) 110 self._kbd_shortcut_map = dict((test.kbd_shortcut, test)
106 for test in test_list) 111 for test in test_list)
107 self.kbd_shortcut_set = set(self._kbd_shortcut_map) 112 self.kbd_shortcut_set = set(self._kbd_shortcut_map)
108 113
109 # Validate keyboard shortcut uniqueness. 114 # Validate keyboard shortcut uniqueness.
110 assert(None not in self.kbd_shortcut_set) 115 assert(None not in self.kbd_shortcut_set)
111 delta = set(test_list) - set(self._kbd_shortcut_map.values()) 116 delta = set(test_list) - set(self._kbd_shortcut_map.values())
112 for test in delta: 117 for test in delta:
113 collision = kbd_shortcut_map[test.kbd_shortcut] 118 collision = kbd_shortcut_map[test.kbd_shortcut]
114 log('ERROR: tests %s and %s both have kbd_shortcut %s' % 119 log('ERROR: tests %s and %s both have kbd_shortcut %s' %
115 (test.label_en, collision.label_en, test.kbd_shortcut)) 120 (test.label_en, collision.label_en, test.kbd_shortcut))
116 assert not delta 121 assert not delta
117 122
118 def get_test_by_details(self, autotest_name, tag_prefix): 123 def get_tag_prefix(self, test):
119 unique_name = '%s.%s' % (autotest_name, tag_prefix) 124 return self._tag_prefix_map[test]
120 return self._unique_name_map.get(unique_name) 125
126 def get_unique_details(self, test):
127 if isinstance(test, AutomatedSequence):
128 return test.subtest_tag_prefix
129 return '%s.%s' % (test.autotest_name, self.get_tag_prefix(test))
130
131 def get_test_by_unique_details(self, autotest_name, tag_prefix):
132 unique_details = '%s.%s' % (autotest_name, tag_prefix)
133 return self._unique_details_map.get(unique_details)
121 134
122 def get_test_by_kbd_shortcut(self, kbd_shortcut): 135 def get_test_by_kbd_shortcut(self, kbd_shortcut):
123 return self._kbd_shortcut_map.get(kbd_shortcut) 136 return self._kbd_shortcut_map.get(kbd_shortcut)
124 137
125 def get_unique_name(self, test): 138 def get_test_by_unique_name(self, unique_name):
126 if isinstance(test, AutomatedSequence): 139 return self._unique_name_map.get(unique_name)
127 return test.subtest_tag_prefix
128 return '%s.%s' % (test.autotest_name, self._tag_prefix_map[test])
129
130 def get_tag_prefix(self, test):
131 return self._tag_prefix_map[test]
132
133 def get_all_tests(self):
134 return set(self.test_queue) | self.subtest_set
135 140
136 def get_subtest_parent(self, test): 141 def get_subtest_parent(self, test):
137 return self._subtest_parent_map.get(test) 142 return self._subtest_parent_map.get(test)
138 143
139 def get_subtest_by_tag_prefix(self, tag_prefix): 144 def get_subtest_by_tag_prefix(self, tag_prefix):
140 return self._subtest_map.get(tag_prefix) 145 return self._subtest_map.get(tag_prefix)
141 146
142 147
143 class StatusMap: 148 class StatusMap:
144 149
145 class Entry: 150 class Entry:
146 151
147 def __init__(self): 152 def __init__(self):
148 self.status = UNTESTED 153 self.status = UNTESTED
149 self.count = 0 154 self.count = 0
150 self.label_box = None 155 self.label_box = None
151 self.error_msg = None 156 self.error_msg = None
152 157
153 def __init__(self, test_list, status_file_path): 158 def __init__(self, test_list, status_file_path):
154 self.test_db = TestDatabase(test_list) 159 self.test_db = TestDatabase(test_list)
155 all_tests = self.test_db.get_all_tests() 160 all_tests = self.test_db.all_tests
156 self._status_map = dict((t, StatusMap.Entry()) for t in all_tests) 161 self._status_map = dict((t, StatusMap.Entry()) for t in all_tests)
157 self._status_file_path = status_file_path 162 self._status_file_path = status_file_path
158 self._status_file_pos = 0 163 self._status_file_pos = 0
159 self.read_new_data() 164 self.read_new_data()
160 165
161 def lookup_status(self, test): 166 def lookup_status(self, test):
162 return self._status_map[test].status 167 return self._status_map[test].status
163 168
164 def lookup_count(self, test): 169 def lookup_count(self, test):
165 return self._status_map[test].count 170 return self._status_map[test].count
(...skipping 14 matching lines...) Expand all
180 185
181 def filter(self, target_status): 186 def filter(self, target_status):
182 comp = (isinstance(target_status, list) and 187 comp = (isinstance(target_status, list) and
183 (lambda s: s in target_status) or 188 (lambda s: s in target_status) or
184 (lambda s: s == target_status)) 189 (lambda s: s == target_status))
185 return [t for t in self.test_db.test_queue 190 return [t for t in self.test_db.test_queue
186 if comp(self.lookup_status(t))] 191 if comp(self.lookup_status(t))]
187 192
188 def next_untested(self): 193 def next_untested(self):
189 remaining = self.filter(UNTESTED) 194 remaining = self.filter(UNTESTED)
190 unique_names = [self.test_db.get_unique_name(t) for t in remaining] 195 unique_details = [self.test_db.get_unique_details(t) for t in remaining]
191 log('remaining untested = [%s]' % ', '.join(unique_names)) 196 log('remaining untested = [%s]' % ', '.join(unique_details))
192 return remaining is not [] and remaining.pop() or None 197 return remaining is not [] and remaining.pop() or None
193 198
194 def read_new_data(self): 199 def read_new_data(self):
195 with open(self._status_file_path) as file: 200 with open(self._status_file_path) as file:
196 file.seek(self._status_file_pos) 201 file.seek(self._status_file_pos)
197 for line in file: 202 for line in file:
198 cols = line.strip().split('\t') + [''] 203 cols = line.strip().split('\t') + ['']
199 code = cols[0] 204 code = cols[0]
200 test_id = cols[1] 205 test_id = cols[1]
201 if code not in STATUS_CODE_MAP or test_id == '----': 206 if code not in STATUS_CODE_MAP or test_id == '----':
202 continue 207 continue
203 status = STATUS_CODE_MAP[code] 208 status = STATUS_CODE_MAP[code]
204 error_msg = status == FAILED and cols[len(cols) - 2] or None 209 error_msg = status == FAILED and cols[len(cols) - 2] or None
205 log('reading code = %s, test_id = %s, error_msg = "%s"' 210 log('reading code = %s, test_id = %s, error_msg = "%s"'
206 % (code, test_id, error_msg)) 211 % (code, test_id, error_msg))
207 autotest_name, _, tag = test_id.rpartition('.') 212 autotest_name, _, tag = test_id.rpartition('.')
208 tag_prefix, _, count = tag.rpartition('_') 213 tag_prefix, _, count = tag.rpartition('_')
209 test = self.test_db.get_test_by_details( 214 test = self.test_db.get_test_by_unique_details(
210 autotest_name, tag_prefix) 215 autotest_name, tag_prefix)
211 if test is None: 216 if test is None:
212 log('ignoring update (%s) for test "%s" "%s"' % 217 log('ignoring update (%s) for test "%s" "%s"' %
213 (status, autotest_name, tag_prefix)) 218 (status, autotest_name, tag_prefix))
214 continue 219 continue
215 self.update(test, status, int(count), error_msg) 220 self.update(test, status, int(count), error_msg)
216 map(self.update_seq_test, self.test_db.seq_test_set) 221 map(self.update_seq_test, self.test_db.seq_test_set)
217 self._status_file_pos = file.tell() 222 self._status_file_pos = file.tell()
218 223
219 def get_active_top_level_test(self): 224 def get_active_top_level_test(self):
220 active_tests = set(self.filter(ACTIVE)) - self.test_db.subtest_set 225 active_tests = set(self.filter(ACTIVE)) - self.test_db.subtest_set
221 return active_tests and active_tests.pop() or None 226 return active_tests and active_tests.pop() or None
222 227
223 def get_active_subtest(self): 228 def get_active_subtest(self):
224 active_subtests = set(self.filter(ACTIVE)) & self.test_db.subtest_set 229 active_subtests = set(self.filter(ACTIVE)) & self.test_db.subtest_set
225 return active_subtests and active_subtests.pop() or None 230 return active_subtests and active_subtests.pop() or None
226 231
227 def register_active(self, test): 232 def register_active(self, test):
228 active_tests = set(self.filter(ACTIVE)) 233 active_tests = set(self.filter(ACTIVE))
229 assert(test not in active_tests) 234 assert(test not in active_tests)
230 if test in self.test_db.subtest_set: 235 if test in self.test_db.subtest_set:
231 parent_seq_test = self.test_db.get_subtest_parent(test) 236 parent_seq_test = self.test_db.get_subtest_parent(test)
232 active_tests -= set([parent_seq_test]) 237 active_tests -= set([parent_seq_test])
233 for bad_test in active_tests: 238 for bad_test in active_tests:
234 unique_name = self.test_db.get_unique_name(bad_test) 239 unique_details = self.test_db.get_unique_details(bad_test)
235 log('WARNING: assuming test %s FAILED (status log has no data)' % 240 log('WARNING: assuming test %s FAILED (status log has no data)' %
236 unique_name) 241 unique_details)
237 self.update(bad_test, FAILED, self.lookup_count(bad_test), 242 self.update(bad_test, FAILED, self.lookup_count(bad_test),
238 'assumed FAILED (status log has no data)') 243 'assumed FAILED (status log has no data)')
239 244
240 def update(self, test, status, count, error_msg): 245 def update(self, test, status, count, error_msg):
241 entry = self._status_map[test] 246 entry = self._status_map[test]
242 unique_name = self.test_db.get_unique_name(test) 247 unique_details = self.test_db.get_unique_details(test)
243 if count < entry.count: 248 if count < entry.count:
244 log('ERROR: count regression for %s (%d -> %d)' % 249 log('ERROR: count regression for %s (%d -> %d)' %
245 (unique_name, entry.count, count)) 250 (unique_details, entry.count, count))
246 if isinstance(test, InformationScreen) and status in [PASSED, FAILED]: 251 if isinstance(test, InformationScreen) and status in [PASSED, FAILED]:
247 status = UNTESTED 252 status = UNTESTED
248 if status != entry.status: 253 if status != entry.status:
249 log('status change for %s : %s/%s -> %s/%s' % 254 log('status change for %s : %s/%s -> %s/%s' %
250 (unique_name, entry.status, entry.count, status, count)) 255 (unique_details, entry.status, entry.count, status, count))
251 if entry.label_box is not None: 256 if entry.label_box is not None:
252 entry.label_box.update(status) 257 entry.label_box.update(status)
253 if status == ACTIVE: 258 if status == ACTIVE:
254 self.register_active(test) 259 self.register_active(test)
255 entry.status = status 260 entry.status = status
256 entry.count = count 261 entry.count = count
257 entry.error_msg = error_msg 262 entry.error_msg = error_msg
258 log('%s new status = %s' % (unique_name, self._status_map[test].status)) 263 log('%s new status = %s' %
264 (unique_details, self._status_map[test].status))
259 265
260 def update_seq_test(self, test): 266 def update_seq_test(self, test):
261 subtest_status_set = set(map(self.lookup_status, test.subtest_list)) 267 subtest_status_set = set(map(self.lookup_status, test.subtest_list))
262 max_count = max(map(self.lookup_count, test.subtest_list)) 268 max_count = max(map(self.lookup_count, test.subtest_list))
263 if len(subtest_status_set) == 1: 269 if len(subtest_status_set) == 1:
264 status = subtest_status_set.pop() 270 status = subtest_status_set.pop()
271 elif subtest_status_set == set([PASSED, FAILED]):
272 status = FAILED
265 else: 273 else:
266 status = ACTIVE in subtest_status_set and ACTIVE or FAILED 274 status = ACTIVE
267 self.update(test, status, max_count, None) 275 self.update(test, status, max_count, None)
268 276
269 def set_label_box(self, test, label_box): 277 def set_label_box(self, test, label_box):
270 entry = self._status_map[test] 278 entry = self._status_map[test]
271 entry.label_box = label_box 279 entry.label_box = label_box
272 label_box.update(entry.status) 280 label_box.update(entry.status)
273 281
274 282
275 class LogData: 283 class LogData:
276 284
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
346 if test.drop_caches: 354 if test.drop_caches:
347 self._job.drop_caches_between_iterations = True 355 self._job.drop_caches_between_iterations = True
348 self._job.run_test(test.autotest_name, **dargs) 356 self._job.run_test(test.autotest_name, **dargs)
349 self._job.drop_caches_between_iterations = False 357 self._job.drop_caches_between_iterations = False
350 self._log_data.read_new_data() 358 self._log_data.read_new_data()
351 activated_ks = self._log_data.shared_dict.pop( 359 activated_ks = self._log_data.shared_dict.pop(
352 'activated_kbd_shortcut', None) 360 'activated_kbd_shortcut', None)
353 lookup = self._status_map.test_db.get_test_by_kbd_shortcut 361 lookup = self._status_map.test_db.get_test_by_kbd_shortcut
354 self.activated_kbd_shortcut_test = ( 362 self.activated_kbd_shortcut_test = (
355 activated_ks and lookup(activated_ks) or None) 363 activated_ks and lookup(activated_ks) or None)
OLDNEW
« no previous file with comments | « no previous file | client/bin/factory_ui » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698