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

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

Issue 2322004: Add support for sequences of fully automated tests. (Closed) Base URL: ssh://git@chromiumos-git/autotest.git
Patch Set: Created 10 years, 6 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
« no previous file with comments | « client/site_tests/factory_Dummy/factory_Dummy.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
(...skipping 13 matching lines...) Expand all
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)
OLDNEW
« no previous file with comments | « client/site_tests/factory_Dummy/factory_Dummy.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698