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

Side by Side Diff: client/site_tests/suite_Factory/control

Issue 3104020: Refactor -- make ui passive watcher, control a passive test list. (Closed) Base URL: http://src.chromium.org/git/autotest.git
Patch Set: rebase against ToT Created 10 years, 3 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
OLDNEW
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 subprocess
28 import sys
29 import time
30
31 imp.load_source('common', job.autodir + '/bin/common.py') 27 imp.load_source('common', job.autodir + '/bin/common.py')
32 from autotest_lib.client.bin import factory 28 from autotest_lib.client.bin import factory
33 from autotest_lib.client.bin import utils 29 from autotest_lib.client.bin import utils
34 30
35 31
36 # -- CUSTOMIZATION -------------------------------------------------- 32 # These definitions are expose these classes directly into this
37 # You can tune these settings to fit your factory process. 33 # namespace, so that the following exec'ed file can have cleaner
38 34 # syntax. These are done in this fashion, as opposed to "from factory
39 # change this to False if you want and allow fast wipe (insecure) 35 # import <class>" to work-around Python namespace wackiness -- the
40 DO_FACTORY_SECURE_WIPE = True 36 # from syntax does not work, creating new classes.
41 37 OperatorTest = factory.OperatorTest
42 # -- END OF CUSTOMIZATION ------------------------------------------ 38 InformationScreen = factory.InformationScreen
39 AutomatedSequence = factory.AutomatedSequence
40 AutomatedSubTest = factory.AutomatedSubTest
41 AutomatedRebootSubTest = factory.AutomatedRebootSubTest
43 42
44 43
45 _RESULTS_PATH = job.autodir + '/results/default' 44 # This exec defines TEST_LIST in global scope.
46 _STATUS_FILE_PATH = _RESULTS_PATH + '/status' 45 execfile(job.autodir + '/site_tests/suite_Factory/test_list')
47 _FACTORY_UI_PATH = job.autodir + '/bin/factory_ui'
48
49
50 _REBOOT_SEQ_ITERATIONS = 2
51 46
52 47
53 # Hack to work around autotest's obsession with GRUB. 48 # Hack to work around autotest's obsession with GRUB.
54 job.bootloader.set_default = lambda x: None 49 job.bootloader.set_default = lambda x: None
55 job.bootloader.boot_once = lambda x: None 50 job.bootloader.boot_once = lambda x: None
56 51
57 52
58 # TEST ORDERING: Tests in the test_list will be run in the order 53 def step_reboot_seq(tag_prefix, total_iterations, i=0):
59 # below, unless the operator interrupts the flow via keyboard 54 if i < total_iterations:
60 # shortcut. To cause immediate execution of the run-in tests, for 55 job.next_step_prepend([step_reboot_seq, tag_prefix,
61 # example, reorder runin to occur as the first test in the test_list. 56 total_iterations, i + 1])
62 57 factory.log('rebooting (iteration %d of %d)' % (i, total_iterations))
63 test_list = [ 58 job.reboot()
64 factory.TestData( 59 else:
65 label_en='start', 60 step_init(intentional_reboot_subtest_tag_prefix=tag_prefix)
66 label_zw='開始',
67 formal_name='factory_Dummy',
68 trigger='e',
69 dargs={'quit_key':ord(' '),
70 'msg':'Hit SPACE to start testing...\n按 "空白鍵" 開始測試...'}),
71 factory.TestData(
72 label_en='sync',
73 label_zw='同步',
74 formal_name='factory_ScriptWrapper',
75 trigger='s',
76 dargs={'cmdline': job.autodir +
77 '/site_tests/factory_ScriptWrapper/dummy.sh'}),
78 factory.TestData(
79 label_en='run-in',
80 label_zw='燒機測試',
81 formal_name='step_runin',
82 automated_seq=[
83 # Match HWQual ID by running hardware_Components with ignored cids.
84 factory.TestData(
85 label_en='hwqual id matching',
86 label_zw='型號匹配',
87 formal_name='hardware_Components',
88 dargs={'approved_dbs':'qualified_components*',
89 'ignored_cids':[
90 'hash_ro_firmware',
91 'part_id_hwqual',
92 'vendor_id_bios',
93 'version_rw_firmware',
94 ]}),
95 factory.TestData(
96 label_en='gpio switch check',
97 label_zw='檢查 gpio 開關',
98 formal_name='hardware_GPIOSwitches'),
99 factory.TestData(
100 label_en='system stress',
101 label_zw='壓力測試',
102 formal_name='hardware_SAT',
103 dargs={'seconds': 60}),
104 factory.TestData(
105 label_en='graphics',
106 label_zw='圖型',
107 formal_name='graphics_GLBench'),
108 factory.TestData(
109 label_en='reboot (%s times)' % _REBOOT_SEQ_ITERATIONS,
110 label_zw='重新開機 (%s 次)' % _REBOOT_SEQ_ITERATIONS,
111 formal_name='factory_RebootStub')],
112 trigger='r'),
113 factory.TestData(
114 label_en='keyboard',
115 label_zw='鍵盤',
116 formal_name='factory_Keyboard',
117 trigger='k',
118 dargs={'layout':'en_us'}),
119 factory.TestData(
120 label_en='touchpad',
121 label_zw='觸控板',
122 formal_name='factory_Touchpad',
123 trigger='t'),
124 factory.TestData(
125 label_en='leds',
126 label_zw='機身側燈',
127 formal_name='factory_Leds',
128 trigger='l',
129 dargs={'led_ctl_path':
130 '/usr/local/autotest/site_tests/factory_Leds/src/ec_ctl'}),
131 factory.TestData(
132 label_en='display',
133 label_zw='顯示',
134 formal_name='factory_Display',
135 trigger='m'),
136 factory.TestData(
137 label_en='ExtDisplay',
138 label_zw='外接顯示',
139 formal_name='factory_ExtDisplay',
140 trigger='n',
141 dargs={'has_audio':True,
142 'sample':'deps/factory/fhorn.wav'}),
143 factory.TestData(
144 label_en='camera',
145 label_zw='相機',
146 formal_name='factory_Camera',
147 trigger='c'),
148 factory.TestData(
149 label_en='audio',
150 label_zw='音源裝置',
151 formal_name='factory_Audio',
152 trigger='a',
153 dargs={'sample':'deps/factory/fhorn.wav'}),
154 factory.TestData(
155 label_en='usb',
156 formal_name='factory_ExternalStorage',
157 trigger='u',
158 dargs={'media':'USB'}),
159 factory.TestData(
160 label_en='sd',
161 formal_name='factory_ExternalStorage',
162 trigger='d',
163 dargs={'media':'SD'}),
164 factory.TestData(
165 label_en='bluetooth',
166 label_zw='藍芽',
167 formal_name='factory_Dummy',
168 trigger='o',
169 dargs={'msg':'bluetooth test, one day...'}),
170 factory.TestData(
171 label_en='3g',
172 label_zw='3G上網',
173 formal_name='factory_Dummy',
174 trigger='g',
175 dargs={'msg':'3g test, one day...'}),
176 factory.TestData(
177 label_en='wifi',
178 label_zw='無線上網',
179 formal_name='factory_Dummy',
180 trigger='w',
181 dargs={'msg':'wifi test, one day...'}),
182 factory.TestData(
183 label_en='light sensor',
184 label_zw='光传感器',
185 formal_name='factory_LightSensor',
186 dargs={'lux_max':1000, 'lux_min':1},
187 trigger='i'),
188
189 # THIS IS A GOOGLE REQUIRED TEST.
190 # PLEASE DO NOT REMOVE THIS TEST IN PRODUCTION RELEASES.
191 factory.TestData(
192 label_en='devrec',
193 label_zw='還原模式',
194 formal_name='factory_DeveloperRecovery',
195 trigger='b',
196 dargs={'layout':'devrec'}),
197
198 # THIS IS A GOOGLE REQUIRED TEST.
199 # PLEASE DO NOT REMOVE THIS TEST IN PRODUCTION RELEASES.
200 factory.TestData(
201 label_en='final',
202 label_zw='最後測試',
203 formal_name='step_final_stage1',
204 automated_seq=[
205 # THIS IS A GOOGLE REQUIRED TEST.
206 # PLEASE DO NOT REMOVE THIS TEST IN PRODUCTION RELEASES.
207 factory.TestData(
208 label_en='write GBB',
209 label_zw='寫入GBB',
210 formal_name='factory_WriteGBB'),
211 factory.TestData(
212 label_en='reboot',
213 label_zw='重新開機',
214 formal_name='factory_RebootStub'),
215 factory.TestData(
216 label_en='component validation',
217 label_zw='元件驗證',
218 formal_name='hardware_Components')],
219 trigger='f'),
220
221 # THIS IS A GOOGLE REQUIRED TEST.
222 # PLEASE DO NOT REMOVE THIS TEST IN PRODUCTION DEVICES.
223 factory.TestData(
224 label_en='wipe',
225 label_zw='清除',
226 formal_name='factory_Wipe',
227 trigger='x',
228 dargs={'secure_wipe':DO_FACTORY_SECURE_WIPE,
229 'write_protect':False,
230 'msg':('hit TAB+ENTER to write protect FW and '
231 'wipe test image!...\n'
232 '請按下 TAB+ENTER 啟用寫入保護以及清除'
233 '測試程式資料!...')}),
234 # NOTE: factory_Wipe.dargs support following variables for temporary
235 # testing. You can add these settings to help internal test, but
236 # THESE ARE GOOGLE REQUIRED TESTS SO YOU SHOULD NOT DISABLE THEM
237 # IN PRODUCTION RELEASES.
238 # - check_developer_switch: check for developer button switch
239 # - write_protect: enable and check flash ROM write protection
240 # TODO(hungte) Although the 'write_protect' should be a Google required
241 # test, we decide to disable it until first official release of
242 # Chrome OS. Please remove that line for the real release.
243
244 factory.TestData(
245 label_en='review',
246 label_zw='報告',
247 formal_name='factory_Review',
248 repeat_forever=True,
249 trigger='z'),
250 ]
251
252 for test in test_list:
253 test.tag_prefix = test.trigger
254 for subtest in test.automated_seq:
255 subtest.tag_prefix = test.formal_name
256
257 test_map = factory.make_test_map(test_list)
258 trigger_set = factory.make_trigger_set(test_list)
259 61
260 62
261 def run_subtest(name, dargs_map): 63 def step_init(intentional_reboot_subtest_tag_prefix=None):
262 job.run_test(name, **dargs_map[name])
263
264
265 def step_reboot_seq(dargs_map, i=0):
266 if i < _REBOOT_SEQ_ITERATIONS:
267 job.next_step_prepend([step_reboot_seq, dargs_map, i + 1])
268 factory.log('rebooting (iteration %d)' % i)
269 time.sleep(5)
270 job.reboot()
271 else:
272 run_subtest('factory_RebootStub', dargs_map)
273 step_init()
274
275
276 hwqual_id = None
277
278 def get_hwqual_id():
279 # TODO: Move HWQual ID to StatusMap.
280 global hwqual_id
281 if not hwqual_id:
282 hwqual_id = find_hwqual_id()
283 return hwqual_id
284
285 def find_hwqual_id():
286 cmd = ('find %s -name keyval | xargs grep -h ^hwqual_id= | '
287 'sed s/hwqual_id=// | head -1' %
288 (_RESULTS_PATH + '/hardware_Components.step_runin_*'))
289 hwqual_id = utils.system_output(cmd).strip()
290 hwqual_id = hwqual_id.rsplit(' ', 1)[0].replace(' ', '_')
291 if not hwqual_id:
292 factory.log('fail to get the HWQual ID')
293 return hwqual_id
294
295
296 def update_dargs(test, dargs_map, update_map):
297 for (key, value) in update_map.iteritems():
298 dargs_map[test][key] = value
299
300
301 def step_runin(ui, dargs_map):
302 run_subtest('hardware_Components', dargs_map)
303 run_subtest('hardware_GPIOSwitches', dargs_map)
304 job.drop_caches_between_iterations = True
305 run_subtest('hardware_SAT', dargs_map)
306 job.drop_caches_between_iterations = False
307 run_subtest('graphics_GLBench', dargs_map)
308 step_reboot_seq(dargs_map)
309
310
311 def step_final_stage1(ui, dargs_map):
312 update_dargs('factory_WriteGBB', dargs_map,
313 {'gbb_file': 'gbb_*%s' % get_hwqual_id()})
314 run_subtest('factory_WriteGBB', dargs_map)
315 job.next_step_prepend([step_final_stage2, ui, dargs_map])
316 factory.log('rebooting')
317 time.sleep(5)
318 job.reboot()
319
320
321 def step_final_stage2(ui, dargs_map):
322 run_subtest('factory_RebootStub', dargs_map)
323 update_dargs('hardware_Components', dargs_map,
324 {'approved_dbs': 'qualified_components_*%s' % get_hwqual_id()})
325 run_subtest('hardware_Components', dargs_map)
326 step_init()
327
328
329 def step_init():
330 '''Launch the factory UI, which will then make decisions on which
331 tests to run in which order. This is to support user driven
332 out-of-order test execution based on keyboard shortcuts.
333
334 For each test, a trigger (possibly None) is communicated to the
335 UI, which then replies with the test name and a count number that
336 becomes the autotest tag to allow repeated test execution while
337 preserving logs.
338
339 When the tests themselves run, they are expected to look for
340 (using the factory_test library) keyboard events that match test
341 switching triggers. When a trigger happens, it should be written
342 to the factory.RESULT_FILE_PATH, which will be read after the test
343 completed and the result comminicated onwards to the UI.'''
344
345 job.next_step([step_init]) 64 job.next_step([step_init])
346 65
347 ui = factory.UiClient(_FACTORY_UI_PATH) 66 factory_ui_path = job.autodir + '/bin/factory_ui'
67 status_file_path = job.autodir + '/results/default/status'
348 68
349 ui.send(test_list) 69 status_map = factory.StatusMap(TEST_LIST, status_file_path)
350 ui.send(_STATUS_FILE_PATH) 70 ui = factory.UiClient(TEST_LIST, factory_ui_path, status_file_path)
71 control_state = factory.ControlState(job, TEST_LIST, ui, status_map,
72 status_file_path)
351 73
352 test_widget_size = ui.recv() 74 if intentional_reboot_subtest_tag_prefix:
353 factory.log('received test_widget_size = %s' % repr(test_widget_size)) 75 reboot_subtest = status_map.test_db.get_subtest_by_tag_prefix(
76 intentional_reboot_subtest_tag_prefix)
77 control_state.run_test(reboot_subtest)
78 status_map.read_new_data()
354 79
355 ui.send_cmd_next_test() 80 test = status_map.next_untested()
356 test, test_count = ui.recv_target_test_update(test_map)
357
358 while test is not None: 81 while test is not None:
359 if test.automated_seq: 82 if isinstance(test, factory.AutomatedSequence):
360 tag = '%s_%s' % (test.formal_name, test_count) 83 for subtest in test.subtest_list:
361 dargs_map = dict((st.formal_name, st.dargs) 84 if isinstance(subtest, factory.AutomatedRebootSubTest):
362 for st in test.automated_seq) 85 tag_prefix = status_map.test_db.get_tag_prefix(subtest)
363 for i in dargs_map: 86 step_reboot_seq(tag_prefix, subtest.iterations)
364 dargs_map[i].update(tag=tag) 87 else:
365 exec('%s(ui, dargs_map)' % (test.formal_name)) 88 control_state.run_test(subtest)
366 result = None 89 if control_state.activated_kbd_shortcut_test:
90 break
367 else: 91 else:
368 dargs = test.dargs 92 control_state.run_test(test)
369 dargs.update({ 93 status_map.read_new_data()
370 'tag': '%s_%s' % (test.tag_prefix, test_count), 94 test = (control_state.activated_kbd_shortcut_test or
371 'test_tag_prefix': test.tag_prefix, 95 status_map.next_untested())
372 'test_count': test_count,
373 'test_widget_size': test_widget_size,
374 'trigger_set': trigger_set,
375 'status_file_path' : _STATUS_FILE_PATH,
376 'test_list': test_list})
377 with open(factory.RESULT_FILE_PATH, 'w') as file:
378 file.write('None\n')
379 job.run_test(test.formal_name, **dargs)
380 with open(factory.RESULT_FILE_PATH, 'r') as file:
381 result = eval(file.readline())
382
383 if result is not None:
384 ui.send_cmd_switch_to(result)
385 else:
386 ui.send_cmd_next_test()
387
388 test, test_count = ui.recv_target_test_update(test_map)
389
390 factory.log('factory testing completed')
OLDNEW
« no previous file with comments | « client/site_tests/factory_ExternalStorage/factory_ExternalStorage.py ('k') | client/site_tests/suite_Factory/test_list » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698