OLD | NEW |
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. |
11 | 11 |
12 | 12 |
| 13 import gobject |
| 14 import signal |
13 import subprocess | 15 import subprocess |
14 import sys | 16 import sys |
15 import time | 17 import time |
16 | 18 |
17 | 19 |
18 ACTIVE = 'ACTIVE' | 20 ACTIVE = 'ACTIVE' |
19 PASSED = 'PASS' | 21 PASSED = 'PASS' |
20 FAILED = 'FAIL' | 22 FAILED = 'FAIL' |
21 UNTESTED = 'UNTESTED' | 23 UNTESTED = 'UNTESTED' |
22 | 24 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 def read_new_data(self): | 201 def read_new_data(self): |
200 with open(self._status_file_path) as file: | 202 with open(self._status_file_path) as file: |
201 file.seek(self._status_file_pos) | 203 file.seek(self._status_file_pos) |
202 for line in file: | 204 for line in file: |
203 cols = line.strip().split('\t') + [''] | 205 cols = line.strip().split('\t') + [''] |
204 code = cols[0] | 206 code = cols[0] |
205 test_id = cols[1] | 207 test_id = cols[1] |
206 if code not in STATUS_CODE_MAP or test_id == '----': | 208 if code not in STATUS_CODE_MAP or test_id == '----': |
207 continue | 209 continue |
208 status = STATUS_CODE_MAP[code] | 210 status = STATUS_CODE_MAP[code] |
| 211 log('cols = %s' % repr(cols)) |
209 error_msg = status == FAILED and cols[len(cols) - 2] or None | 212 error_msg = status == FAILED and cols[len(cols) - 2] or None |
210 log('reading code = %s, test_id = %s, error_msg = "%s"' | 213 log('reading code = %s, test_id = %s, error_msg = "%s"' |
211 % (code, test_id, error_msg)) | 214 % (code, test_id, error_msg)) |
212 autotest_name, _, tag = test_id.rpartition('.') | 215 autotest_name, _, tag = test_id.rpartition('.') |
213 tag_prefix, _, count = tag.rpartition('_') | 216 tag_prefix, _, count = tag.rpartition('_') |
214 test = self.test_db.get_test_by_unique_details( | 217 test = self.test_db.get_test_by_unique_details( |
215 autotest_name, tag_prefix) | 218 autotest_name, tag_prefix) |
216 if test is None: | 219 if test is None: |
217 log('ignoring update (%s) for test "%s" "%s"' % | 220 log('ignoring update (%s) for test "%s" "%s"' % |
218 (status, autotest_name, tag_prefix)) | 221 (status, autotest_name, tag_prefix)) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 file.seek(self._log_file_pos) | 295 file.seek(self._log_file_pos) |
293 for line in file: | 296 for line in file: |
294 parts = line.rsplit(DATA_PREFIX, 1) | 297 parts = line.rsplit(DATA_PREFIX, 1) |
295 if not len(parts) == 2: | 298 if not len(parts) == 2: |
296 continue | 299 continue |
297 key, raw_value = parts.pop().strip().split('=', 1) | 300 key, raw_value = parts.pop().strip().split('=', 1) |
298 log('updating shared_dict[%s]=%s' % (key, raw_value)) | 301 log('updating shared_dict[%s]=%s' % (key, raw_value)) |
299 self.shared_dict[key] = eval(raw_value) | 302 self.shared_dict[key] = eval(raw_value) |
300 self._log_file_pos = file.tell() | 303 self._log_file_pos = file.tell() |
301 | 304 |
302 | 305 def get(self, key): |
303 class UiClient: | 306 return self.shared_dict.get(key) |
304 '''Support communication with the factory_ui process. To simplify | |
305 surrounding code, this communication is an exchange of well formed | |
306 python expressions. Basically send wraps its arguments in a call | |
307 to repr() and recv calls eval() to re-generate the python data.''' | |
308 | |
309 def __init__(self, test_list, factory_ui_path, status_file_path): | |
310 self._proc = subprocess.Popen(factory_ui_path, | |
311 stdin=subprocess.PIPE, | |
312 stdout=subprocess.PIPE) | |
313 self.send(test_list) | |
314 self.send(status_file_path) | |
315 self.test_widget_size = self.recv() | |
316 log('control received test_widget_size = %s' % | |
317 repr(self.test_widget_size)) | |
318 | |
319 def __del__(self): | |
320 log('control deleting factory_ui subprocess') | |
321 self._proc.terminate() | |
322 time.sleep(1) | |
323 if self._proc.poll() is None: | |
324 self._proc.kill() | |
325 | |
326 def send(self, x=None): | |
327 print >> self._proc.stdin, repr(x) | |
328 self._proc.stdin.flush() | |
329 | |
330 def recv(self): | |
331 return eval(self._proc.stdout.readline().rstrip()) | |
332 | 307 |
333 | 308 |
334 class ControlState: | 309 class ControlState: |
335 | 310 |
336 def __init__(self, job, test_list, ui, status_map, status_file_path): | 311 def __init__(self, job, test_list, status_map, status_file_path, nuke_fn): |
337 self._job = job | 312 self._job = job |
338 self._status_map = status_map | 313 self._status_map = status_map |
339 self._log_data = LogData() | 314 self._log_data = LogData() |
340 self._std_dargs = { | 315 self._std_dargs = { |
341 'test_widget_size': ui.test_widget_size, | |
342 'trigger_set': status_map.test_db.kbd_shortcut_set, | |
343 'status_file_path' : status_file_path, | 316 'status_file_path' : status_file_path, |
344 'test_list': test_list} | 317 'test_list': test_list} |
| 318 self._nuke_fn = nuke_fn |
| 319 self.activated_kbd_shortcut_test = None |
| 320 signal.signal(signal.SIGUSR1, self.kill_current_test_callback) |
| 321 |
| 322 log('waiting for ui to come up...') |
| 323 while self._log_data.get('test_widget_size') is None: |
| 324 time.sleep(1) |
| 325 self._log_data.read_new_data() |
| 326 |
| 327 def kill_current_test_callback(self, signum, frame): |
| 328 self._log_data.read_new_data() |
| 329 active_test_data = self._log_data.get('active_test_data') |
| 330 log('KILLING active_test_data %s' % repr(active_test_data)) |
| 331 if active_test_data is not None: |
| 332 self._nuke_fn(*active_test_data) |
345 | 333 |
346 def run_test(self, test): | 334 def run_test(self, test): |
347 self._status_map.incr_count(test) | 335 self._status_map.incr_count(test) |
| 336 self._log_data.read_new_data() |
| 337 test_tag = self._status_map.lookup_tag(test) |
348 dargs = {} | 338 dargs = {} |
349 dargs.update(test.dargs) | 339 dargs.update(test.dargs) |
350 dargs.update(self._std_dargs) | 340 dargs.update(self._std_dargs) |
351 test_tag = self._status_map.lookup_tag(test) | |
352 dargs.update({'tag': test_tag, | 341 dargs.update({'tag': test_tag, |
353 'subtest_tag': test_tag, | 342 'subtest_tag': test_tag, |
354 'shared_dict': self._log_data.shared_dict}) | 343 'shared_dict': self._log_data.shared_dict}) |
| 344 |
| 345 self._job.factory_shared_dict = self._log_data.shared_dict |
| 346 |
| 347 log('control shared dict = %s' % repr(self._log_data.shared_dict)) |
| 348 |
355 if test.drop_caches: | 349 if test.drop_caches: |
356 self._job.drop_caches_between_iterations = True | 350 self._job.drop_caches_between_iterations = True |
| 351 self.activated_kbd_shortcut_test = None |
| 352 |
357 self._job.run_test(test.autotest_name, **dargs) | 353 self._job.run_test(test.autotest_name, **dargs) |
| 354 |
358 self._job.drop_caches_between_iterations = False | 355 self._job.drop_caches_between_iterations = False |
359 self._log_data.read_new_data() | 356 self._log_data.read_new_data() |
360 activated_ks = self._log_data.shared_dict.pop( | 357 kbd_shortcut = self._log_data.shared_dict.pop( |
361 'activated_kbd_shortcut', None) | 358 'activated_kbd_shortcut', None) |
362 lookup = self._status_map.test_db.get_test_by_kbd_shortcut | 359 if kbd_shortcut is not None: |
363 self.activated_kbd_shortcut_test = ( | 360 test_db = self._status_map.test_db |
364 activated_ks and lookup(activated_ks) or None) | 361 target_test = test_db.get_test_by_kbd_shortcut(kbd_shortcut) |
| 362 self.activated_kbd_shortcut_test = target_test |
| 363 log('kbd_shortcut %s -> %s)' % ( |
| 364 kbd_shortcut, test_db.get_unique_details(target_test))) |
OLD | NEW |