OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
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 | 7 |
8 # DESCRIPTION : | 8 # DESCRIPTION : |
9 # | 9 # |
10 # This UI is intended to be used by the factory autotest suite to | 10 # This UI is intended to be used by the factory autotest suite to |
11 # provide factory operators feedback on test status and control over | 11 # provide factory operators feedback on test status and control over |
12 # execution order. | 12 # execution order. |
13 # | 13 # |
14 # In short, the UI is composed of a 'console' panel on the bottom of | 14 # In short, the UI is composed of a 'console' panel on the bottom of |
15 # the screen which displays the autotest log, and there is also a | 15 # the screen which displays the autotest log, and there is also a |
16 # 'test list' panel on the right hand side of the screen. The | 16 # 'test list' panel on the right hand side of the screen. The |
17 # majority of the screen is dedicated to tests, which are executed in | 17 # majority of the screen is dedicated to tests, which are executed in |
18 # seperate processes, but instructed to display their own UIs in this | 18 # seperate processes, but instructed to display their own UIs in this |
19 # dedicated area whenever possible. Tests in the test list are | 19 # dedicated area whenever possible. Tests in the test list are |
20 # executed in order by default, but can be activated on demand via | 20 # executed in order by default, but can be activated on demand via |
21 # associated keyboard shortcuts (triggers). As tests are run, their | 21 # associated keyboard shortcuts. As tests are run, their status is |
22 # status is color-indicated to the operator -- greyed out means | 22 # color-indicated to the operator -- greyed out means untested, yellow |
23 # untested, yellow means active, green passed and red failed. | 23 # means active, green passed and red failed. |
24 | 24 |
25 | 25 |
26 import gobject | 26 import gobject |
27 import gtk | 27 import gtk |
28 import imp | 28 import imp |
29 import os | 29 import os |
30 import pango | 30 import pango |
31 import subprocess | 31 import subprocess |
32 import sys | 32 import sys |
33 import time | 33 import time |
34 | 34 |
35 import common | 35 import common |
36 import factory | 36 import factory |
37 import factory_ui_lib as ful | 37 import factory_ui_lib as ful |
38 | 38 |
39 from factory import TestData | 39 |
| 40 # These definitions are expose these classes directly into this |
| 41 # namespace, so that the test_list that is sent from the control file |
| 42 # can have cleaner syntax. These are done in this fashion, as opposed |
| 43 # to "from factory import <class>" to work-around Python namespace |
| 44 # wackiness -- the from syntax does not work, creating new classes. |
| 45 OperatorTest = factory.OperatorTest |
| 46 InformationScreen = factory.InformationScreen |
| 47 AutomatedSequence = factory.AutomatedSequence |
| 48 AutomatedSubTest = factory.AutomatedSubTest |
| 49 AutomatedRebootSubTest = factory.AutomatedRebootSubTest |
40 | 50 |
41 | 51 |
42 _SEP_COLOR = gtk.gdk.color_parse('grey50') | 52 _SEP_COLOR = gtk.gdk.color_parse('grey50') |
43 | 53 |
44 _LABEL_EN_SIZE = (160, 35) | 54 _LABEL_EN_SIZE = (170, 35) |
45 _LABEL_ZW_SIZE = (70, 35) | 55 _LABEL_ZW_SIZE = (70, 35) |
46 _LABEL_EN_FONT = pango.FontDescription('courier new extra-condensed 16') | 56 _LABEL_EN_FONT = pango.FontDescription('courier new extra-condensed 16') |
47 _LABEL_ZW_FONT = pango.FontDescription('normal 12') | 57 _LABEL_ZW_FONT = pango.FontDescription('normal 12') |
48 _LABEL_T_SIZE = (30, 35) | 58 _LABEL_T_SIZE = (30, 35) |
49 _LABEL_T_FONT = pango.FontDescription('courier new italic ultra-condensed 10') | 59 _LABEL_T_FONT = pango.FontDescription('courier new italic ultra-condensed 10') |
50 _LABEL_UNTESTED_FG = gtk.gdk.color_parse('grey40') | 60 _LABEL_UNTESTED_FG = gtk.gdk.color_parse('grey40') |
51 _LABEL_TROUGH_COLOR = gtk.gdk.color_parse('grey20') | 61 _LABEL_TROUGH_COLOR = gtk.gdk.color_parse('grey20') |
52 _LABEL_STATUS_SIZE = (140, 30) | 62 _LABEL_STATUS_SIZE = (140, 30) |
53 _LABEL_STATUS_FONT = pango.FontDescription( | 63 _LABEL_STATUS_FONT = pango.FontDescription( |
54 'courier new bold extra-condensed 16') | 64 'courier new bold extra-condensed 16') |
55 _OTHER_LABEL_FONT = pango.FontDescription('courier new condensed 20') | 65 _OTHER_LABEL_FONT = pango.FontDescription('courier new condensed 20') |
56 | 66 |
57 _ST_LABEL_EN_SIZE = (250, 35) | 67 _ST_LABEL_EN_SIZE = (250, 35) |
58 _ST_LABEL_ZW_SIZE = (150, 35) | 68 _ST_LABEL_ZW_SIZE = (150, 35) |
59 | 69 |
60 _STATUS_REFRESH_MS = 200 | 70 _STATUS_REFRESH_MS = 100 |
61 | 71 |
62 class Console: | 72 class Console: |
63 '''Display a progress log. Implemented by launching an borderless | 73 '''Display a progress log. Implemented by launching an borderless |
64 xterm at a strategic location, and running tail against the log.''' | 74 xterm at a strategic location, and running tail against the log.''' |
65 | 75 |
66 def __init__(self, allocation): | 76 def __init__(self, allocation): |
67 xterm_coords = '135x14+%d+%d' % (allocation.x, allocation.y) | 77 xterm_coords = '135x14+%d+%d' % (allocation.x, allocation.y) |
68 factory.log('xterm_coords = %s' % xterm_coords) | 78 factory.log('xterm_coords = %s' % xterm_coords) |
69 xterm_cmd = (('aterm --geometry %s -bw 0 -e bash -c ' % | 79 xterm_cmd = (('aterm --geometry %s -bw 0 -e bash -c ' % |
70 xterm_coords).split() + | 80 xterm_coords).split() + |
71 ['tail -f %s | grep FACTORY' % factory.LOG_PATH]) | 81 ['tail -f %s | grep FACTORY' % factory.LOG_PATH]) |
72 factory.log('xterm_cmd = %s' % xterm_cmd) | 82 factory.log('xterm_cmd = %s' % xterm_cmd) |
73 self._proc = subprocess.Popen(xterm_cmd) | 83 self._proc = subprocess.Popen(xterm_cmd) |
74 | 84 |
75 def __del__(self): | 85 def __del__(self): |
76 factory.log('console_proc __del__') | 86 factory.log('console_proc __del__') |
77 self._proc.kill() | 87 self._proc.kill() |
78 | 88 |
79 | 89 |
80 # Routines to communicate with the autotest control file, using python | |
81 # expressions. The stdin_callback assures notification for any new | |
82 # messages. | |
83 | |
84 def stdin_callback(s, c): | |
85 factory.log('stdin_callback, quitting gtk main') | |
86 gtk.main_quit() | |
87 return True | |
88 | |
89 def control_recv(): | |
90 return eval(sys.stdin.readline().rstrip()) | |
91 | |
92 def control_send(x): | |
93 print repr(x) | |
94 sys.stdout.flush() | |
95 | |
96 def control_send_target_test_update(test, count): | |
97 factory.log('ui send_target_test_update %s.%s_%s' % | |
98 (test.formal_name, test.tag_prefix, count)) | |
99 control_send((test.formal_name, test.tag_prefix, count)) | |
100 | |
101 | |
102 # Capture keyboard events here for debugging -- under normal | 90 # Capture keyboard events here for debugging -- under normal |
103 # circumstances, all keyboard events should be captured by executing | 91 # circumstances, all keyboard events should be captured by executing |
104 # tests, and hence this should not be called. | 92 # tests, and hence this should not be called. |
105 | 93 |
106 def handle_key_release_event(_, event): | 94 def handle_key_release_event(_, event): |
107 factory.log('base ui key event (%s)' % event.keyval) | 95 factory.log('base ui key event (%s)' % event.keyval) |
108 return True | 96 return True |
109 | 97 |
110 | 98 |
111 class TestLabelBox(gtk.EventBox): | 99 class TestLabelBox(gtk.EventBox): |
112 | 100 |
113 def __init__(self, test): | 101 def __init__(self, test): |
114 gtk.EventBox.__init__(self) | 102 gtk.EventBox.__init__(self) |
115 self.modify_bg(gtk.STATE_NORMAL, ful.LABEL_COLORS[ful.UNTESTED]) | 103 self.modify_bg(gtk.STATE_NORMAL, ful.LABEL_COLORS[ful.UNTESTED]) |
116 label_en = gtk.Label(test.label_en) | 104 |
117 label_en.set_size_request(*_LABEL_EN_SIZE) | 105 label_en = ful.make_label(test.label_en, size=_LABEL_EN_SIZE, |
118 label_en.modify_font(_LABEL_EN_FONT) | 106 font=_LABEL_EN_FONT, alignment=(0.5, 0.5), |
119 label_en.set_alignment(0.5, 0.5) | 107 fg=_LABEL_UNTESTED_FG) |
120 label_en.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) | 108 label_zw = ful.make_label(test.label_zw, size=_LABEL_ZW_SIZE, |
121 label_zw = gtk.Label(test.label_zw) | 109 font=_LABEL_ZW_FONT, alignment=(0.5, 0.5), |
122 label_zw.set_size_request(*_LABEL_ZW_SIZE) | 110 fg=_LABEL_UNTESTED_FG) |
123 label_zw.modify_font(_LABEL_ZW_FONT) | 111 label_t = ful.make_label('C-' + test.kbd_shortcut, size=_LABEL_T_SIZE, |
124 label_zw.set_alignment(0.5, 0.5) | 112 font=_LABEL_T_FONT, alignment=(0.5, 0.5), |
125 label_zw.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) | 113 fg=ful.BLACK) |
126 label_t = gtk.Label('C-' + test.trigger) | |
127 label_t.set_size_request(*_LABEL_T_SIZE) | |
128 label_t.modify_font(_LABEL_T_FONT) | |
129 label_t.set_alignment(0.5, 0.5) | |
130 label_t.modify_fg(gtk.STATE_NORMAL, ful.BLACK) | |
131 hbox = gtk.HBox() | 114 hbox = gtk.HBox() |
132 hbox.pack_start(label_en, False, False) | 115 hbox.pack_start(label_en, False, False) |
133 hbox.pack_start(label_zw, False, False) | 116 hbox.pack_start(label_zw, False, False) |
134 hbox.pack_start(label_t, False, False) | 117 hbox.pack_start(label_t, False, False) |
135 self.add(hbox) | 118 self.add(hbox) |
136 self.label_list = [label_en, label_zw] | 119 self.label_list = [label_en, label_zw] |
137 | 120 |
138 def update(self, status): | 121 def update(self, status): |
139 label_fg = status == ful.UNTESTED and _LABEL_UNTESTED_FG or ful.BLACK | 122 label_fg = status == ful.UNTESTED and _LABEL_UNTESTED_FG or ful.BLACK |
140 for label in self.label_list: | 123 for label in self.label_list: |
141 label.modify_fg(gtk.STATE_NORMAL, label_fg) | 124 label.modify_fg(gtk.STATE_NORMAL, label_fg) |
142 self.modify_bg(gtk.STATE_NORMAL, ful.LABEL_COLORS[status]) | 125 self.modify_bg(gtk.STATE_NORMAL, ful.LABEL_COLORS[status]) |
143 self.queue_draw() | 126 self.queue_draw() |
144 | 127 |
145 | 128 |
146 class SubTestLabelBox(gtk.EventBox): | 129 class SubTestLabelBox(gtk.EventBox): |
147 | 130 |
148 def __init__(self, test): | 131 def __init__(self, test): |
149 gtk.EventBox.__init__(self) | 132 gtk.EventBox.__init__(self) |
150 self.modify_bg(gtk.STATE_NORMAL, ful.BLACK) | 133 self.modify_bg(gtk.STATE_NORMAL, ful.BLACK) |
151 label_status = gtk.Label(ful.UNTESTED) | 134 label_status = ful.make_label(ful.UNTESTED, size=_LABEL_STATUS_SIZE, |
152 label_status.set_size_request(*_LABEL_STATUS_SIZE) | 135 alignment=(0, 0.5), |
153 label_status.set_alignment(0, 0.5) | 136 font=_LABEL_STATUS_FONT, |
154 label_status.modify_font(_LABEL_STATUS_FONT) | 137 fg=_LABEL_UNTESTED_FG) |
155 label_status.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) | 138 label_sep = ful.make_label(' : ', alignment=(0.5, 0.5), |
156 label_sep = gtk.Label(' : ') | 139 font=_LABEL_EN_FONT) |
157 label_sep.set_alignment(0.5, 0.5) | 140 label_en = ful.make_label(test.label_en, size=_ST_LABEL_EN_SIZE, |
158 label_sep.modify_font(_LABEL_EN_FONT) | 141 alignment=(0.5, 0.5), |
159 label_sep.modify_fg(gtk.STATE_NORMAL, ful.LIGHT_GREEN) | 142 font=_LABEL_EN_FONT) |
160 label_en = gtk.Label(test.label_en) | 143 label_zw = ful.make_label(test.label_zw, size=_ST_LABEL_ZW_SIZE, |
161 label_en.set_size_request(*_ST_LABEL_EN_SIZE) | 144 alignment=(0.5, 0.5), font=_LABEL_ZW_FONT) |
162 label_en.set_alignment(0.5, 0.5) | |
163 label_en.modify_font(_LABEL_EN_FONT) | |
164 label_en.modify_fg(gtk.STATE_NORMAL, ful.LIGHT_GREEN) | |
165 label_zw = gtk.Label(test.label_zw) | |
166 label_zw.set_size_request(*_ST_LABEL_ZW_SIZE) | |
167 label_zw.set_alignment(0.5, 0.5) | |
168 label_zw.modify_font(_LABEL_ZW_FONT) | |
169 label_zw.modify_fg(gtk.STATE_NORMAL, ful.LIGHT_GREEN) | |
170 hbox = gtk.HBox() | 145 hbox = gtk.HBox() |
171 hbox.pack_end(label_status, False, False) | 146 hbox.pack_end(label_status, False, False) |
172 hbox.pack_end(label_sep, False, False) | 147 hbox.pack_end(label_sep, False, False) |
173 hbox.pack_end(label_zw, False, False) | 148 hbox.pack_end(label_zw, False, False) |
174 hbox.pack_end(label_en, False, False) | 149 hbox.pack_end(label_en, False, False) |
175 self.add(hbox) | 150 self.add(hbox) |
176 self.label_status = label_status | 151 self.label_status = label_status |
177 | 152 |
178 def update(self, status): | 153 def update(self, status): |
179 if status == ful.UNTESTED: | 154 if status == ful.UNTESTED: |
180 return | 155 return |
181 self.label_status.set_text(status) | 156 self.label_status.set_text(status) |
182 self.label_status.modify_fg(gtk.STATE_NORMAL, ful.LABEL_COLORS[status]) | 157 self.label_status.modify_fg(gtk.STATE_NORMAL, ful.LABEL_COLORS[status]) |
183 self.queue_draw() | 158 self.queue_draw() |
184 | 159 |
185 | 160 |
| 161 class UiState(): |
| 162 |
| 163 def __init__(self, window, status_map, test_widget_box): |
| 164 |
| 165 def make_empty_test_label_widget(): |
| 166 label_box = gtk.EventBox() |
| 167 label_box.modify_bg(gtk.STATE_NORMAL, ful.BLACK) |
| 168 label = ful.make_label('no active test', font=_OTHER_LABEL_FONT, |
| 169 alignment=(0.5, 0.5)) |
| 170 label_box.add(label) |
| 171 return label_box |
| 172 |
| 173 def make_automated_seq_label_widget(subtest_list): |
| 174 vbox = gtk.VBox() |
| 175 vbox.set_spacing(0) |
| 176 for subtest in subtest_list: |
| 177 label_box = SubTestLabelBox(subtest) |
| 178 status_map.set_label_box(subtest, label_box) |
| 179 vbox.pack_start(status_map.lookup_label_box(subtest), |
| 180 False, False) |
| 181 return vbox |
| 182 |
| 183 self._window = window |
| 184 self._status_map = status_map |
| 185 self._test_widget_box = test_widget_box |
| 186 self._empty_test_widget = make_empty_test_label_widget() |
| 187 self._active_test_widget = self._empty_test_widget |
| 188 self.active_test = None |
| 189 |
| 190 self._test_widget_box.add(self._empty_test_widget) |
| 191 |
| 192 self._automated_seq_widget_map = dict( |
| 193 (t, make_automated_seq_label_widget(t.subtest_list)) |
| 194 for t in self._status_map.test_db.seq_test_set) |
| 195 |
| 196 def set_active_test(self, test): |
| 197 '''Control what kind of widget is shown in the testing area of |
| 198 the screen. For normal operator tests, this is just a label |
| 199 saying there is no active test. The expectation is that the |
| 200 operator test itself has a window obscuring this message. For |
| 201 automated sequences, since there is no other window, the no |
| 202 active test message is replaced with an updated list of |
| 203 subtest status.''' |
| 204 if test == self.active_test: |
| 205 return |
| 206 self.active_test = test |
| 207 self._test_widget_box.remove(self._active_test_widget) |
| 208 active_widget = (test in self._status_map.test_db.seq_test_set |
| 209 and self._automated_seq_widget_map[test] |
| 210 or self._empty_test_widget) |
| 211 self._test_widget_box.add(active_widget) |
| 212 self._active_test_widget = active_widget |
| 213 self._window.show_all() |
| 214 |
| 215 |
186 def make_hsep(width=1): | 216 def make_hsep(width=1): |
187 frame = gtk.EventBox() | 217 frame = gtk.EventBox() |
188 frame.set_size_request(-1, width) | 218 frame.set_size_request(-1, width) |
189 frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR) | 219 frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR) |
190 return frame | 220 return frame |
191 | 221 |
192 | 222 |
193 def make_vsep(width=1): | 223 def make_vsep(width=1): |
194 frame = gtk.EventBox() | 224 frame = gtk.EventBox() |
195 frame.set_size_request(width, -1) | 225 frame.set_size_request(width, -1) |
196 frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR) | 226 frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR) |
197 return frame | 227 return frame |
198 | 228 |
199 | 229 |
200 def make_notest_label(): | 230 def refresh_status(status_map, ui_state): |
201 label = gtk.Label('no active test') | 231 status_map.read_new_data() |
202 label.modify_font(_OTHER_LABEL_FONT) | 232 active_test = status_map.get_active_top_level_test() |
203 label.set_alignment(0.5, 0.5) | 233 ui_state.set_active_test(active_test) |
204 label.modify_fg(gtk.STATE_NORMAL, ful.LIGHT_GREEN) | 234 return True |
205 box = gtk.EventBox() | |
206 box.modify_bg(gtk.STATE_NORMAL, ful.BLACK) | |
207 box.add(label) | |
208 return box | |
209 | |
210 | |
211 def make_automated_seq_widget(as_test, status_map): | |
212 vbox = gtk.VBox() | |
213 vbox.set_spacing(0) | |
214 map(lambda st: vbox.pack_start(status_map.lookup_label(st), False, False), | |
215 as_test.automated_seq) | |
216 return vbox | |
217 | 235 |
218 | 236 |
219 def main(): | 237 def main(): |
| 238 '''This process is launched by the autotest suite_Factory control |
| 239 process. Communication with this process is an exchange of well |
| 240 formed python expressions over stdin and stdout. Basically |
| 241 sending wraps arguments in a call to repr() and recv calls eval() |
| 242 to re-generate the python data.''' |
| 243 |
| 244 def control_recv(): |
| 245 return eval(sys.stdin.readline().rstrip()) |
| 246 |
| 247 def control_send(x): |
| 248 print repr(x) |
| 249 sys.stdout.flush() |
| 250 |
| 251 # On startup, get the list of tests to run (in order) and the |
| 252 # autotest status file path. |
| 253 factory.log('pulling control info') |
| 254 test_list = control_recv() |
| 255 status_file_path = control_recv() |
| 256 |
| 257 status_map = factory.StatusMap(test_list, status_file_path) |
| 258 |
220 window = gtk.Window(gtk.WINDOW_TOPLEVEL) | 259 window = gtk.Window(gtk.WINDOW_TOPLEVEL) |
221 window.connect('destroy', lambda _: gtk.main_quit()) | 260 window.connect('destroy', lambda _: gtk.main_quit()) |
222 window.modify_bg(gtk.STATE_NORMAL, ful.BLACK) | 261 window.modify_bg(gtk.STATE_NORMAL, ful.BLACK) |
223 | 262 |
224 screen = window.get_screen() | 263 screen = window.get_screen() |
225 screen_size = (screen.get_width(), screen.get_height()) | 264 screen_size = (screen.get_width(), screen.get_height()) |
226 window.set_size_request(*screen_size) | 265 window.set_size_request(*screen_size) |
227 | 266 |
228 label_trough = gtk.VBox() | 267 label_trough = gtk.VBox() |
229 label_trough.set_spacing(0) | 268 label_trough.set_spacing(0) |
230 | 269 |
231 rhs_box = gtk.EventBox() | 270 rhs_box = gtk.EventBox() |
232 rhs_box.modify_bg(gtk.STATE_NORMAL, _LABEL_TROUGH_COLOR) | 271 rhs_box.modify_bg(gtk.STATE_NORMAL, _LABEL_TROUGH_COLOR) |
233 rhs_box.add(label_trough) | 272 rhs_box.add(label_trough) |
234 | 273 |
235 console_box = gtk.EventBox() | 274 console_box = gtk.EventBox() |
236 console_box.set_size_request(-1, 180) | 275 console_box.set_size_request(-1, 180) |
237 console_box.modify_bg(gtk.STATE_NORMAL, ful.BLACK) | 276 console_box.modify_bg(gtk.STATE_NORMAL, ful.BLACK) |
238 | 277 |
239 notest_label = make_notest_label() | |
240 | |
241 test_widget_box = gtk.Alignment(xalign=0.5, yalign=0.5) | 278 test_widget_box = gtk.Alignment(xalign=0.5, yalign=0.5) |
242 test_widget_box.set_size_request(-1, -1) | 279 test_widget_box.set_size_request(-1, -1) |
243 test_widget_box.add(notest_label) | 280 |
| 281 ui_state = UiState(window, status_map, test_widget_box) |
244 | 282 |
245 lhs_box = gtk.VBox() | 283 lhs_box = gtk.VBox() |
246 lhs_box.pack_end(console_box, False, False) | 284 lhs_box.pack_end(console_box, False, False) |
247 lhs_box.pack_start(test_widget_box) | 285 lhs_box.pack_start(test_widget_box) |
248 lhs_box.pack_start(make_hsep(3), False, False) | 286 lhs_box.pack_start(make_hsep(3), False, False) |
249 | 287 |
250 base_box = gtk.HBox() | 288 base_box = gtk.HBox() |
251 base_box.pack_end(rhs_box, False, False) | 289 base_box.pack_end(rhs_box, False, False) |
252 base_box.pack_end(make_vsep(3), False, False) | 290 base_box.pack_end(make_vsep(3), False, False) |
253 base_box.pack_start(lhs_box) | 291 base_box.pack_start(lhs_box) |
254 | 292 |
255 window.connect('key-release-event', handle_key_release_event) | 293 window.connect('key-release-event', handle_key_release_event) |
256 window.add_events(gtk.gdk.KEY_RELEASE_MASK) | 294 window.add_events(gtk.gdk.KEY_RELEASE_MASK) |
257 | 295 |
258 # On startup, get general configuration data from the autotest | 296 gobject.timeout_add(_STATUS_REFRESH_MS, refresh_status, |
259 # control program, specifically the list of tests to run (in | 297 status_map, ui_state) |
260 # order) and some filenames. | |
261 factory.log('pulling control info') | |
262 test_list = control_recv() | |
263 status_file_path = control_recv() | |
264 | |
265 status_map = ful.StatusMap(status_file_path, test_list) | |
266 gobject.timeout_add(_STATUS_REFRESH_MS, status_map.read_new_data) | |
267 | 298 |
268 for test in test_list: | 299 for test in test_list: |
269 tlb = TestLabelBox(test) | 300 label_box = TestLabelBox(test) |
270 status_map.set_label(test, tlb) | 301 status_map.set_label_box(test, label_box) |
271 label_trough.pack_start(tlb, False, False) | 302 label_trough.pack_start(label_box, False, False) |
272 label_trough.pack_start(make_hsep(), False, False) | 303 label_trough.pack_start(make_hsep(), False, False) |
273 for subtest in test.automated_seq: | |
274 stlb = SubTestLabelBox(subtest) | |
275 status_map.set_label(subtest, stlb) | |
276 | 304 |
277 window.add(base_box) | 305 window.add(base_box) |
278 window.show_all() | 306 window.show_all() |
279 | 307 |
280 ful.hide_cursor(window.window) | 308 ful.hide_cursor(window.window) |
281 | 309 |
282 test_widget_allocation = test_widget_box.get_allocation() | 310 test_widget_allocation = test_widget_box.get_allocation() |
283 test_widget_size = (test_widget_allocation.width, | 311 test_widget_size = (test_widget_allocation.width, |
284 test_widget_allocation.height) | 312 test_widget_allocation.height) |
285 factory.log('test_widget_size = %s' % repr(test_widget_size)) | 313 factory.log('test_widget_size = %s' % repr(test_widget_size)) |
286 control_send(test_widget_size) | 314 control_send(test_widget_size) |
287 | 315 |
288 trigger_dict = dict((test.trigger, test) for test in test_list) | |
289 | |
290 gobject.io_add_watch(sys.stdin, gobject.IO_IN, stdin_callback) | |
291 | |
292 console = Console(console_box.get_allocation()) | 316 console = Console(console_box.get_allocation()) |
293 | 317 |
294 factory.log('finished ui setup') | 318 factory.log('factory_ui setup done, starting gtk.main()...') |
295 | 319 |
296 # Test selection is driven either by triggers or by the | 320 gtk.main() |
297 # remaining_tests_queue. If a trigger was seen, explicitly run | |
298 # the corresponding test. Otherwise choose the next test from the | |
299 # queue. Tests are removed from the queue as they are run, | |
300 # regarless of the outcome. Tests that are interrupted by trigger | |
301 # are treated as having failed. | |
302 # | |
303 # Iterations in the main loop here are driven by data availability | |
304 # on stdin, which is used to communicate with the autotest control | |
305 # program. On each step through the loop, a trigger is received | |
306 # (possibly None) to indicate how the next test should be selected. | |
307 | 321 |
308 while True: | 322 factory.log('factory_ui gtk.main() finished, exiting.') |
309 command, arg = control_recv() | |
310 factory.log('ui received command %s(%s)' % (command, arg)) | |
311 if command == 'switch_to': | |
312 next_test = trigger_dict.get(arg, None) | |
313 elif command == 'next_test': | |
314 next_test = status_map.next_untested() | |
315 else: | |
316 factory.log('ui command unknown, exiting...') | |
317 break | |
318 control_send_target_test_update( | |
319 next_test, status_map.lookup_count(next_test) + 1) | |
320 if next_test.automated_seq: | |
321 factory.log('ui starting automated_seq') | |
322 test_widget_box.remove(notest_label) | |
323 as_widget = make_automated_seq_widget(next_test, status_map) | |
324 test_widget_box.add(as_widget) | |
325 window.show_all() | |
326 gtk.main() | |
327 command = control_recv() | |
328 factory.log('ui automated_seq cmd (%s)' % command) | |
329 test_widget_box.remove(as_widget) | |
330 test_widget_box.add(notest_label) | |
331 window.show_all() | |
332 factory.log('ui exiting automated_seq') | |
333 else: | |
334 gtk.main() | |
335 | |
336 # Tell the control process we are done. | |
337 control_send((None, 0)) | |
338 | |
339 factory.log('exiting ui') | |
340 | 323 |
341 if __name__ == '__main__': | 324 if __name__ == '__main__': |
342 main() | 325 main() |
OLD | NEW |