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 AUTHOR = "Chrome OS Team" | 7 AUTHOR = "Chrome OS Team" |
8 NAME = "Factory" | 8 NAME = "Factory" |
9 TIME = "LONG" | 9 TIME = "LONG" |
10 TEST_CATEGORY = "Functional" | 10 TEST_CATEGORY = "Functional" |
11 TEST_CLASS = "suite" | 11 TEST_CLASS = "suite" |
12 TEST_TYPE = "client" | 12 TEST_TYPE = "client" |
13 | 13 |
14 DOC = """ | 14 DOC = """ |
15 This suite executed all of the factory tests, and incorporates an | 15 This suite executed all of the factory tests, and incorporates an |
16 X-windows GTK-based UI to highlight testing results and to allow | 16 X-windows GTK-based UI to highlight testing results and to allow |
17 factory operators to switch between tests, and to re-run tests, all | 17 factory operators to switch between tests, and to re-run tests, all |
18 on-demand via keyboard shortcuts. | 18 on-demand via keyboard shortcuts. |
19 | 19 |
20 The UI is implemented as a seperate process (see _FACTORY_UI_PATH), | 20 The UI is implemented as a seperate process (see _FACTORY_UI_PATH), |
21 which means that interprocess communication is needed between this | 21 which means that interprocess communication is needed between this |
22 control, the UI, and the tests (which are forked children of this | 22 control, the UI, and the tests (which are forked children of this |
23 control process). """ | 23 control process). """ |
24 | 24 |
25 | 25 |
26 import imp | 26 import imp |
| 27 import os |
| 28 |
27 imp.load_source('common', job.autodir + '/bin/common.py') | 29 imp.load_source('common', job.autodir + '/bin/common.py') |
| 30 |
28 from autotest_lib.client.bin import factory | 31 from autotest_lib.client.bin import factory |
29 from autotest_lib.client.bin import utils | 32 from autotest_lib.client.bin import parallel |
| 33 |
| 34 |
| 35 FACTORY_UI_PATH = job.autodir + '/bin/factory_ui' |
| 36 STATUS_FILE_PATH = job.autodir + '/results/default/status' |
| 37 TEST_LIST_PATH = job.autodir + '/site_tests/suite_Factory/test_list' |
| 38 |
| 39 |
| 40 # Hack to grab the pid for forked tests. |
| 41 |
| 42 from autotest_lib.client.bin.parallel import fork_waitfor as orig_fork_waitfor |
| 43 |
| 44 def new_fork_waitfor(tmp, pid): |
| 45 factory.log_shared_data('active_test_data', (tmp, pid)) |
| 46 orig_fork_waitfor(tmp, pid) |
| 47 |
| 48 parallel.fork_waitfor = new_fork_waitfor |
30 | 49 |
31 | 50 |
32 # These definitions are expose these classes directly into this | 51 # These definitions are expose these classes directly into this |
33 # namespace, so that the following exec'ed file can have cleaner | 52 # namespace, so that the following exec'ed file can have cleaner |
34 # syntax. These are done in this fashion, as opposed to "from factory | 53 # syntax. These are done in this fashion, as opposed to "from factory |
35 # import <class>" to work-around Python namespace wackiness -- the | 54 # import <class>" to work-around Python namespace wackiness -- the |
36 # from syntax does not work, creating new classes. | 55 # from syntax does not work, creating new classes. |
37 OperatorTest = factory.OperatorTest | 56 OperatorTest = factory.OperatorTest |
38 InformationScreen = factory.InformationScreen | 57 InformationScreen = factory.InformationScreen |
39 AutomatedSequence = factory.AutomatedSequence | 58 AutomatedSequence = factory.AutomatedSequence |
40 AutomatedSubTest = factory.AutomatedSubTest | 59 AutomatedSubTest = factory.AutomatedSubTest |
41 AutomatedRebootSubTest = factory.AutomatedRebootSubTest | 60 AutomatedRebootSubTest = factory.AutomatedRebootSubTest |
42 | 61 |
43 | 62 |
44 # This exec defines TEST_LIST in global scope. | 63 # This exec defines TEST_LIST in global scope. |
45 execfile(job.autodir + '/site_tests/suite_Factory/test_list') | 64 execfile(TEST_LIST_PATH) |
46 | 65 |
47 | 66 |
48 # Hack to work around autotest's obsession with GRUB. | 67 # Hack to work around autotest's obsession with GRUB. |
49 job.bootloader.set_default = lambda x: None | 68 job.bootloader.set_default = lambda x: None |
50 job.bootloader.boot_once = lambda x: None | 69 job.bootloader.boot_once = lambda x: None |
51 | 70 |
52 | 71 |
53 def step_reboot_seq(tag_prefix, total_iterations, i=0): | 72 def step_reboot_seq(tag_prefix, total_iterations, i=0): |
54 if i < total_iterations: | 73 if i < total_iterations: |
55 job.next_step_prepend([step_reboot_seq, tag_prefix, | 74 job.next_step_prepend([step_reboot_seq, tag_prefix, |
56 total_iterations, i + 1]) | 75 total_iterations, i + 1]) |
57 factory.log('rebooting (iteration %d of %d)' % (i, total_iterations)) | 76 factory.log('rebooting (iteration %d of %d)' % (i, total_iterations)) |
58 job.reboot() | 77 job.reboot() |
59 else: | 78 else: |
60 step_init(intentional_reboot_subtest_tag_prefix=tag_prefix) | 79 step_init(intentional_reboot_subtest_tag_prefix=tag_prefix) |
61 | 80 |
62 | 81 |
63 def step_init(intentional_reboot_subtest_tag_prefix=None): | 82 def step_init(intentional_reboot_subtest_tag_prefix=None): |
64 job.next_step([step_init]) | 83 job.next_step([step_init]) |
65 | 84 |
66 factory_ui_path = job.autodir + '/bin/factory_ui' | 85 ui_proc_args = [FACTORY_UI_PATH, TEST_LIST_PATH, |
67 status_file_path = job.autodir + '/results/default/status' | 86 STATUS_FILE_PATH, str(os.getpid())] |
| 87 factory.log('starting ui -- %s' % repr(ui_proc_args)) |
| 88 ui_proc = subprocess.Popen(ui_proc_args) |
68 | 89 |
69 status_map = factory.StatusMap(TEST_LIST, status_file_path) | 90 status_map = factory.StatusMap(TEST_LIST, STATUS_FILE_PATH) |
70 ui = factory.UiClient(TEST_LIST, factory_ui_path, status_file_path) | 91 control_state = factory.ControlState( |
71 control_state = factory.ControlState(job, TEST_LIST, ui, status_map, | 92 job, TEST_LIST, status_map, STATUS_FILE_PATH, |
72 status_file_path) | 93 parallel.fork_nuke_subprocess) |
73 | 94 |
74 if intentional_reboot_subtest_tag_prefix: | 95 if intentional_reboot_subtest_tag_prefix: |
75 reboot_subtest = status_map.test_db.get_subtest_by_tag_prefix( | 96 reboot_subtest = status_map.test_db.get_subtest_by_tag_prefix( |
76 intentional_reboot_subtest_tag_prefix) | 97 intentional_reboot_subtest_tag_prefix) |
77 control_state.run_test(reboot_subtest) | 98 control_state.run_test(reboot_subtest) |
78 status_map.read_new_data() | 99 status_map.read_new_data() |
79 | 100 |
80 test = status_map.next_untested() | 101 test = status_map.next_untested() |
81 while test is not None: | 102 while test is not None: |
| 103 factory.log('next test = %s' % |
| 104 status_map.test_db.get_unique_details(test)) |
82 if isinstance(test, factory.AutomatedSequence): | 105 if isinstance(test, factory.AutomatedSequence): |
83 for subtest in test.subtest_list: | 106 for subtest in test.subtest_list: |
84 if isinstance(subtest, factory.AutomatedRebootSubTest): | 107 if isinstance(subtest, factory.AutomatedRebootSubTest): |
85 tag_prefix = status_map.test_db.get_tag_prefix(subtest) | 108 tag_prefix = status_map.test_db.get_tag_prefix(subtest) |
86 step_reboot_seq(tag_prefix, subtest.iterations) | 109 step_reboot_seq(tag_prefix, subtest.iterations) |
87 else: | 110 else: |
88 control_state.run_test(subtest) | 111 control_state.run_test(subtest) |
89 if control_state.activated_kbd_shortcut_test: | 112 if control_state.activated_kbd_shortcut_test: |
90 break | 113 break |
91 else: | 114 else: |
92 control_state.run_test(test) | 115 control_state.run_test(test) |
93 status_map.read_new_data() | 116 status_map.read_new_data() |
94 test = (control_state.activated_kbd_shortcut_test or | 117 test = (control_state.activated_kbd_shortcut_test or |
95 status_map.next_untested()) | 118 status_map.next_untested()) |
OLD | NEW |