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" |
(...skipping 13 matching lines...) Expand all Loading... | |
24 | 24 |
25 | 25 |
26 import subprocess | 26 import subprocess |
27 import sys | 27 import sys |
28 import time | 28 import time |
29 | 29 |
30 | 30 |
31 _FACTORY_LOG_PATH = '/var/log/factory.log' | 31 _FACTORY_LOG_PATH = '/var/log/factory.log' |
32 _RESULT_FILE_PATH = '/var/run/factory_test_result' | 32 _RESULT_FILE_PATH = '/var/run/factory_test_result' |
33 | 33 |
34 _REBOOT_SEQ_ITERATIONS = 2 | |
35 | |
34 | 36 |
35 def XXX_log(s): | 37 def XXX_log(s): |
36 print >> sys.stderr, '--- XXX : ' + s | 38 print >> sys.stderr, '--- XXX : ' + s |
37 | 39 |
38 | 40 |
39 # Hack to work around autotest's obsession with GRUB. | 41 # Hack to work around autotest's obsession with GRUB. |
40 job.bootloader.set_default = lambda x: None | 42 job.bootloader.set_default = lambda x: None |
41 job.bootloader.boot_once = lambda x: None | 43 job.bootloader.boot_once = lambda x: None |
42 | 44 |
43 | 45 |
44 class factory_ui: | |
45 '''Support communication with the factory_ui process. To simplify | |
46 surrounding code, this communication is an exchange of well formed | |
47 python expressions. Basically send wraps its arguments in a call | |
48 to repr() and recv calls eval() to re-generate the python data.''' | |
49 | |
50 def __init__(self, factory_ui_path): | |
51 self._proc = subprocess.Popen(factory_ui_path, | |
52 stdin=subprocess.PIPE, | |
53 stdout=subprocess.PIPE) | |
54 | |
55 def __del__(self): | |
56 XXX_log('factory_ui __del__') | |
57 self._proc.terminate() | |
58 time.sleep(1) | |
59 if self._proc.poll() is None: | |
60 self._proc.kill() | |
61 | |
62 def send(self, x): | |
63 print >> self._proc.stdin, repr(x) | |
64 self._proc.stdin.flush() | |
65 | |
66 def recv(self): | |
67 return eval(self._proc.stdout.readline().rstrip()) | |
68 | |
69 | |
70 # This is the definition of the test_data class, which holds | 46 # This is the definition of the test_data class, which holds |
71 # factory-specific information on the tests to be run. Specifically, | 47 # factory-specific information on the tests to be run. Specifically, |
72 # the order of items in the list reflect the order they are to be run | 48 # the order of items in the list reflect the order they are to be run |
73 # on the line. The label and trigger fields contain the description | 49 # on the line. The label and trigger fields contain the description |
74 # strings to be shown in the test control list of the UI. The trigger | 50 # strings to be shown in the test control list of the UI. The trigger |
75 # field specifies the keyboard shortcut to allow on-demain | 51 # field specifies the keyboard shortcut to allow on-demain |
76 # out-of-order test activation. The dargs field allows test specific | 52 # out-of-order test activation. The dargs field allows test specific |
77 # extra arguments. Note: this datastructure is defined as a string | 53 # extra arguments. Note: this datastructure is defined as a string |
78 # and exec()ed to allow it to be defined once here, but to be also | 54 # and exec()ed to allow it to be defined once here, but to be also |
79 # used by the factory_ui process. | 55 # used by the factory_ui process. |
80 | 56 |
81 test_data_class_def = ''' | 57 test_data_class_def = ''' |
82 class test_data: | 58 class test_data: |
83 | 59 |
84 def __init__(self, label_en='', label_zw='', formal_name='', | 60 def __init__(self, label_en='', label_zw='', formal_name=None, |
85 trigger=None, dargs={}): | 61 tag_prefix=None, trigger=None, automated_seq=[], dargs={}): |
86 self.__dict__.update(vars()) | 62 self.__dict__.update(vars()) |
87 | 63 |
88 def __repr__(self): | 64 def __repr__(self): |
89 d = ['%s=%s' % (l,repr(v)) | 65 d = ['%s=%s' % (l,repr(v)) |
90 for l,v in self.__dict__.items() | 66 for l,v in self.__dict__.items() |
91 if l != 'self'] | 67 if l != 'self'] |
92 c = ('%s' % self.__class__).rpartition('.')[2] | 68 c = ('%s' % self.__class__).rpartition('.')[2] |
93 return '%s(%s)' % (c, ','.join(d)) | 69 return '%s(%s)' % (c, ','.join(d)) |
94 ''' | 70 ''' |
95 exec(test_data_class_def) | 71 exec(test_data_class_def) |
96 | 72 |
97 | 73 |
98 test_list = [ | 74 test_list = [ |
99 test_data( | 75 test_data( |
100 label_en='dummy A', | 76 label_en='start', |
101 formal_name='factory_Dummy', | 77 formal_name='factory_Dummy', |
102 trigger='a', | 78 trigger='a', |
103 dargs={'msg':'Hello World'}), | 79 dargs={'quit_key':ord(' '), |
80 'msg':'Hit SPACE to start testing...\n按 "空白鍵" 開始測試...'}), | |
104 test_data( | 81 test_data( |
105 label_en='dummy B', | 82 label_en='run-in', |
106 formal_name='factory_Dummy', | 83 formal_name='step_runin', |
107 trigger='b', | 84 automated_seq=[ |
108 dargs={'msg':'Hello Factory'}), | 85 test_data( |
86 label_en='component validation', | |
87 formal_name='hardware_Components'), | |
88 test_data( | |
89 label_en='gpio switch check', | |
90 formal_name='hardware_GPIOSwitches'), | |
91 test_data( | |
92 label_en='system stress', | |
93 formal_name='hardware_SAT'), | |
Nick Sanders
2010/06/02 08:06:36
is there any way to get the test list specified in
Tammo Spalink
2010/06/07 03:40:21
You mean like scrape the names out from the step_r
| |
94 test_data( | |
95 label_en='reboot (%s times)' % _REBOOT_SEQ_ITERATIONS, | |
96 formal_name='factory_RebootStub')], | |
97 trigger='r'), | |
109 test_data( | 98 test_data( |
110 label_en='dummy C', | 99 label_en='camera', |
111 formal_name='factory_Dummy', | 100 formal_name='factory_Dummy', |
112 trigger='c', | 101 trigger='c', |
113 dargs={'msg':'Hello Mom...'}), | 102 dargs={'msg':'camera test, one day...'}), |
114 test_data( | 103 test_data( |
115 label_en='keyboard', | 104 label_en='keyboard', |
116 label_zw='鍵盤', | 105 label_zw='鍵盤', |
117 formal_name='factory_Keyboard', | 106 formal_name='factory_Keyboard', |
118 trigger='k', | 107 trigger='k', |
119 dargs={'layout':'en_us'}), | 108 dargs={'layout':'en_us'}), |
120 test_data( | 109 test_data( |
121 label_en='trackpad', | 110 label_en='trackpad', |
122 label_zw='觸控板', | 111 label_zw='觸控板', |
123 formal_name='hardware_Touchpad', | 112 formal_name='hardware_Touchpad', |
124 trigger='t'), | 113 trigger='t'), |
125 ] | 114 ] |
126 | 115 |
116 for test in test_list: | |
117 test.tag_prefix = test.trigger | |
118 for subtest in test.automated_seq: | |
119 subtest.tag_prefix = test.formal_name | |
127 | 120 |
128 test_map = dict((test.label_en, test) for test in test_list) | 121 def test_map_index(formal_name, tag_prefix): |
122 return formal_name + '.' + tag_prefix | |
129 | 123 |
124 test_map = dict((test_map_index(test.formal_name, test.tag_prefix), test) | |
125 for test in test_list) | |
130 | 126 |
131 trigger_set = set(test.trigger for test in test_list) | 127 trigger_set = set(test.trigger for test in test_list) |
132 | 128 |
133 | 129 |
134 def step_init(): | 130 class factory_ui: |
135 job.next_step([step_run_ui]) | 131 '''Support communication with the factory_ui process. To simplify |
136 step_run_ui() | 132 surrounding code, this communication is an exchange of well formed |
133 python expressions. Basically send wraps its arguments in a call | |
134 to repr() and recv calls eval() to re-generate the python data.''' | |
135 | |
136 def __init__(self, factory_ui_path): | |
137 self._proc = subprocess.Popen(factory_ui_path, | |
138 stdin=subprocess.PIPE, | |
139 stdout=subprocess.PIPE) | |
140 | |
141 def __del__(self): | |
142 XXX_log('control deleting factory_ui subprocess') | |
143 self._proc.terminate() | |
144 time.sleep(1) | |
145 if self._proc.poll() is None: | |
146 self._proc.kill() | |
147 | |
148 def send(self, x=None): | |
149 print >> self._proc.stdin, repr(x) | |
150 self._proc.stdin.flush() | |
151 | |
152 def send_cmd_next_test(self): | |
153 self.send(('next_test', None)) | |
154 | |
155 def send_cmd_switch_to(self, trigger): | |
156 self.send(('switch_to', trigger)) | |
157 | |
158 def recv(self): | |
159 return eval(self._proc.stdout.readline().rstrip()) | |
160 | |
161 def recv_target_test_update(self): | |
162 update = self.recv() | |
163 XXX_log('control recv target test %s' % repr(update)) | |
164 formal_name, tag_prefix, count = update | |
165 test = test_map.get(test_map_index(formal_name, tag_prefix), None) | |
166 if test is not None: | |
167 test.count = count | |
168 return test | |
137 | 169 |
138 | 170 |
139 def step_run_ui(): | 171 def step_reboot_seq(i, tag): |
172 if i < _REBOOT_SEQ_ITERATIONS: | |
173 job.next_step([step_reboot_seq, i + 1, tag]) | |
174 XXX_log('rebooting (iteration %d)' % i) | |
175 time.sleep(5) | |
176 job.reboot() | |
177 else: | |
178 job.run_test('factory_RebootStub', tag=tag) | |
179 step_init() | |
180 | |
181 | |
182 def step_runin(ui, tag): | |
183 job.run_test('hardware_Components', | |
184 approved_db='qualified_components', | |
185 tag=tag) | |
186 ui.send() | |
187 job.run_test('hardware_GPIOSwitches', tag=tag) | |
188 ui.send() | |
189 job.drop_caches_between_iterations = True | |
190 job.run_test('hardware_SAT', tag=tag) | |
191 job.drop_caches_between_iterations = False | |
192 ui.send() | |
193 step_reboot_seq(0, tag) | |
194 | |
195 | |
196 def step_init(): | |
197 | |
140 '''Launch the factory UI, which will then make decisions on which | 198 '''Launch the factory UI, which will then make decisions on which |
141 tests to run in which order. This is to support user driven | 199 tests to run in which order. This is to support user driven |
142 out-of-order test execution based on keyboard shortcuts. | 200 out-of-order test execution based on keyboard shortcuts. |
143 | 201 |
144 For each test, a trigger (possibly None) is communicated to the | 202 For each test, a trigger (possibly None) is communicated to the |
145 UI, which then replies with the test name and a count number that | 203 UI, which then replies with the test name and a count number that |
146 becomes the autotest tag to allow repeated test execution while | 204 becomes the autotest tag to allow repeated test execution while |
147 preserving logs. | 205 preserving logs. |
148 | 206 |
149 When the tests themselves run, they are expected to look for | 207 When the tests themselves run, they are expected to look for |
150 (using the factory_test library) keyboard events that match test | 208 (using the factory_test library) keyboard events that match test |
151 switching triggers. When a trigger happens, it should be written | 209 switching triggers. When a trigger happens, it should be written |
152 to the _RESULT_FILE_PATH, which will be read after the test | 210 to the _RESULT_FILE_PATH, which will be read after the test |
153 completed and the result comminicated onwards to the UI.''' | 211 completed and the result comminicated onwards to the UI.''' |
154 | 212 |
155 status_file_path = job.autodir + '/results/default/status' | 213 status_file_path = job.autodir + '/results/default/status' |
156 factory_ui_path = job.autodir + '/factory_ui' | 214 factory_ui_path = job.autodir + '/factory_ui' |
157 | 215 |
158 ui = factory_ui(factory_ui_path) | 216 ui = factory_ui(factory_ui_path) |
159 | 217 |
160 ui.send(test_data_class_def) | 218 ui.send(test_data_class_def) |
161 ui.send(test_list) | 219 ui.send(test_list) |
162 ui.send(status_file_path) | 220 ui.send(status_file_path) |
163 ui.send(_FACTORY_LOG_PATH) | 221 ui.send(_FACTORY_LOG_PATH) |
164 | 222 |
165 test_widget_size = ui.recv() | 223 test_widget_size = ui.recv() |
166 XXX_log('received test_widget_size = %s' % repr(test_widget_size)) | 224 XXX_log('received test_widget_size = %s' % repr(test_widget_size)) |
167 | 225 |
168 # Send initial 'None' trigger. | 226 ui.send_cmd_next_test() |
169 ui.send(None) | 227 test = ui.recv_target_test_update() |
170 | 228 |
171 while True: | 229 while test is not None: |
172 next_test_name, count = ui.recv() | 230 if test.automated_seq: |
231 tag = '%s_%s' % (test.formal_name, test.count) | |
232 exec('%s(ui, "%s")' % (test.formal_name, tag)) | |
233 result = None | |
234 else: | |
235 dargs = test.dargs | |
236 dargs.update({ | |
237 'tag': '%s_%s' % (test.tag_prefix, test.count), | |
238 'test_widget_size': test_widget_size, | |
239 'trigger_set': trigger_set, | |
240 'result_file_path': _RESULT_FILE_PATH}) | |
241 with open(_RESULT_FILE_PATH, 'w') as file: | |
242 file.write('None\n') | |
243 job.run_test(test.formal_name, **dargs) | |
244 with open(_RESULT_FILE_PATH, 'r') as file: | |
245 result = eval(file.readline()) | |
173 | 246 |
174 XXX_log('next_test_name = %s , count = %s' % (next_test_name, count)) | 247 if result is not None: |
175 if next_test_name is None: | 248 ui.send_cmd_switch_to(result) |
176 XXX_log('factory testing completed') | 249 else: |
177 break | 250 ui.send_cmd_next_test() |
178 | 251 |
179 test = test_map[next_test_name] | 252 test = ui.recv_target_test_update() |
180 dargs = test.dargs | |
181 dargs.update({ | |
182 'tag': str(count), | |
183 'test_widget_size': test_widget_size, | |
184 'trigger_set': trigger_set, | |
185 'result_file_path': _RESULT_FILE_PATH}) | |
186 | 253 |
187 with open(_RESULT_FILE_PATH, 'w') as file: | 254 XXX_log('factory testing completed') |
188 file.write('None\n') | |
189 job.run_test(test.formal_name, **dargs) | |
190 with open(_RESULT_FILE_PATH, 'r') as file: | |
191 result = eval(file.readline()) | |
192 ui.send(result) | |
OLD | NEW |