OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 # | 2 # |
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 | 7 |
8 # DESCRIPTION : | 8 # DESCRIPTION : |
9 # | 9 # |
10 # This library provides convenience routines to launch factory tests. | 10 # This library provides convenience routines to launch factory tests. |
11 # This includes support for identifying keyboard test switching | 11 # This includes support for identifying keyboard test switching |
12 # triggers, grabbing control of the keyboard and mouse, and making the | 12 # triggers, grabbing control of the keyboard and mouse, and making the |
13 # mouse cursor disappear. It also manages communication of any found | 13 # mouse cursor disappear. It also manages communication of any found |
14 # keyboard triggers to the control process, via writing data to | 14 # keyboard triggers to the control process, via writing data to |
15 # factory.RESULT_FILE_PATH. | 15 # factory.RESULT_FILE_PATH. |
16 | 16 |
17 | 17 |
18 from autotest_lib.client.bin import factory | 18 from autotest_lib.client.bin import factory |
19 from autotest_lib.client.common_lib import error | 19 from autotest_lib.client.common_lib import error |
20 | 20 |
| 21 from factory import ACTIVE, PASSED, FAILED, UNTESTED, STATUS_CODE_MAP |
| 22 |
21 import cairo | 23 import cairo |
22 import gtk | 24 import gtk |
23 import pango | 25 import pango |
24 import sys | 26 import sys |
25 | 27 |
26 | 28 |
27 BLACK = gtk.gdk.Color() | 29 BLACK = gtk.gdk.Color() |
28 RED = gtk.gdk.Color(0xFFFF, 0, 0) | 30 RED = gtk.gdk.Color(0xFFFF, 0, 0) |
29 GREEN = gtk.gdk.Color(0, 0xFFFF, 0) | 31 GREEN = gtk.gdk.Color(0, 0xFFFF, 0) |
30 BLUE = gtk.gdk.Color(0, 0, 0xFFFF) | 32 BLUE = gtk.gdk.Color(0, 0, 0xFFFF) |
31 WHITE = gtk.gdk.Color(0xFFFF, 0xFFFF, 0xFFFF) | 33 WHITE = gtk.gdk.Color(0xFFFF, 0xFFFF, 0xFFFF) |
32 | 34 |
33 LIGHT_GREEN = gtk.gdk.color_parse('light green') | 35 LIGHT_GREEN = gtk.gdk.color_parse('light green') |
34 | 36 |
35 RGBA_GREEN_OVERLAY = (0, 0.5, 0, 0.6) | 37 RGBA_GREEN_OVERLAY = (0, 0.5, 0, 0.6) |
36 RGBA_YELLOW_OVERLAY = (0.6, 0.6, 0, 0.6) | 38 RGBA_YELLOW_OVERLAY = (0.6, 0.6, 0, 0.6) |
37 | 39 |
38 ACTIVE = 'ACTIVE' | |
39 PASSED = 'PASS' | |
40 FAILED = 'FAIL' | |
41 UNTESTED = 'UNTESTED' | |
42 | |
43 STATUS_CODE_MAP = { | |
44 'START': ACTIVE, | |
45 'GOOD': PASSED, | |
46 'FAIL': FAILED, | |
47 'ERROR': FAILED} | |
48 | |
49 LABEL_COLORS = { | 40 LABEL_COLORS = { |
50 ACTIVE: gtk.gdk.color_parse('light goldenrod'), | 41 ACTIVE: gtk.gdk.color_parse('light goldenrod'), |
51 PASSED: gtk.gdk.color_parse('pale green'), | 42 PASSED: gtk.gdk.color_parse('pale green'), |
52 FAILED: gtk.gdk.color_parse('tomato'), | 43 FAILED: gtk.gdk.color_parse('tomato'), |
53 UNTESTED: gtk.gdk.color_parse('dark slate grey')} | 44 UNTESTED: gtk.gdk.color_parse('dark slate grey')} |
54 | 45 |
55 LABEL_FONT = pango.FontDescription('courier new condensed 16') | 46 LABEL_FONT = pango.FontDescription('courier new condensed 16') |
56 | 47 |
57 FAIL_TIMEOUT = 30 | 48 FAIL_TIMEOUT = 30 |
58 | 49 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 factory.log('factory_test running gtk.main') | 128 factory.log('factory_test running gtk.main') |
138 gtk.main() | 129 gtk.main() |
139 factory.log('factory_test quit gtk.main') | 130 factory.log('factory_test quit gtk.main') |
140 | 131 |
141 if cleanup_callback is not None: | 132 if cleanup_callback is not None: |
142 cleanup_callback() | 133 cleanup_callback() |
143 | 134 |
144 gtk.gdk.pointer_ungrab() | 135 gtk.gdk.pointer_ungrab() |
145 gtk.gdk.keyboard_ungrab() | 136 gtk.gdk.keyboard_ungrab() |
146 | 137 |
147 if self._got_trigger is None: | 138 if self._got_trigger is not None: |
148 return | 139 factory.log('run_test_widget returning kbd_shortcut "%s"' % |
149 with open(factory.RESULT_FILE_PATH, 'w') as file: | 140 self._got_trigger) |
150 file.write('%s\n' % repr(self._got_trigger)) | 141 factory.log_shared_data('activated_kbd_shortcut', self._got_trigger) |
151 raise error.TestFail('explicit test switch triggered (%s)' % | |
152 self._got_trigger) | |
153 | |
154 | |
155 class StatusMap(): | |
156 | |
157 def __init__(self, status_file_path, test_list): | |
158 self._test_queue = [t for t in reversed(test_list)] | |
159 self._as_test_set = set(t for t in test_list if t.automated_seq) | |
160 self._status_map = {} | |
161 for test in test_list: | |
162 test_index = self.index(test.formal_name, test.tag_prefix) | |
163 self._status_map[test_index] = (test, UNTESTED, 0, None, None) | |
164 for subtest in test.automated_seq: | |
165 st_index = self.index(subtest.formal_name, subtest.tag_prefix) | |
166 self._status_map[st_index] = (subtest, UNTESTED, 0, None, None) | |
167 self._status_file_path = status_file_path | |
168 self._status_file_pos = 0 | |
169 self.read_new_data() | |
170 | |
171 def index(self, formal_name, tag_prefix): | |
172 return '%s.%s' % (formal_name, tag_prefix) | |
173 | |
174 def filter(self, target_status): | |
175 comp = (isinstance(target_status, list) and | |
176 (lambda s: s in target_status) or | |
177 (lambda s: s == target_status)) | |
178 return [t for t in self._test_queue if comp(self.lookup_status(t))] | |
179 | |
180 def next_untested(self): | |
181 remaining = self.filter(UNTESTED) | |
182 factory.log('remaining untested = [%s]' % | |
183 ', '.join([self.index(t.formal_name, t.tag_prefix) | |
184 for t in remaining])) | |
185 if not remaining: return None | |
186 return remaining.pop() | |
187 | |
188 def read_new_data(self): | |
189 with open(self._status_file_path) as file: | |
190 file.seek(self._status_file_pos) | |
191 for line in file: | |
192 cols = line.strip().split('\t') + [''] | |
193 code = cols[0] | |
194 test_id = cols[1] | |
195 if code not in STATUS_CODE_MAP or test_id == '----': | |
196 continue | |
197 status = STATUS_CODE_MAP[code] | |
198 error = status == FAILED and cols[len(cols) - 2] or None | |
199 factory.log('reading code = %s, test_id = %s, error_msg = "%s"' | |
200 % (code, test_id, error)) | |
201 formal_name, _, tag = test_id.rpartition('.') | |
202 tag_prefix, _, count = tag.rpartition('_') | |
203 self.update(formal_name, tag_prefix, status, int(count), error) | |
204 self._status_file_pos = file.tell() | |
205 map(self.update_as_test, self._as_test_set) | |
206 return True | |
207 | |
208 def update(self, formal_name, tag_prefix, status, count, error): | |
209 test_index = self.index(formal_name, tag_prefix) | |
210 if test_index not in self._status_map: | |
211 factory.log('ignoring status update (%s) for test %s' % | |
212 (status, test_index)) | |
213 return | |
214 test, old_status, old_count, label, _ = self._status_map[test_index] | |
215 if count < old_count: | |
216 factory.log('ERROR: count regression for %s (%d-%d)' % | |
217 (test_index, old_count, count)) | |
218 if test.repeat_forever and status in [PASSED, FAILED]: | |
219 status = UNTESTED | |
220 if status != old_status: | |
221 factory.log('status change for %s : %s/%s -> %s/%s' % | |
222 (test_index, old_status, old_count, status, count)) | |
223 if label is not None: | |
224 label.update(status) | |
225 self._status_map[test_index] = (test, status, count, label, error) | |
226 | |
227 def update_as_test(self, test): | |
228 st_status_set = set(map(self.lookup_status, test.automated_seq)) | |
229 max_count = max(map(self.lookup_count, test.automated_seq)) | |
230 if len(st_status_set) == 1: | |
231 status = st_status_set.pop() | |
232 else: | |
233 status = ACTIVE in st_status_set and ACTIVE or FAILED | |
234 self.update(test.formal_name, test.tag_prefix, status, max_count, None) | |
235 | |
236 def set_label(self, test, label): | |
237 test_index = self.index(test.formal_name, test.tag_prefix) | |
238 test, status, count, _, error = self._status_map[test_index] | |
239 label.update(status) | |
240 self._status_map[test_index] = test, status, count, label, error | |
241 | |
242 def lookup_status(self, test): | |
243 test_index = self.index(test.formal_name, test.tag_prefix) | |
244 return self._status_map[test_index][1] | |
245 | |
246 def lookup_count(self, test): | |
247 test_index = self.index(test.formal_name, test.tag_prefix) | |
248 return self._status_map[test_index][2] | |
249 | |
250 def lookup_label(self, test): | |
251 test_index = self.index(test.formal_name, test.tag_prefix) | |
252 return self._status_map[test_index][3] | |
253 | |
254 def lookup_error(self, test): | |
255 test_index = self.index(test.formal_name, test.tag_prefix) | |
256 return self._status_map[test_index][4] | |
OLD | NEW |