Index: src/scripts/mod_for_factory_scripts/factory_ui |
diff --git a/src/scripts/mod_for_factory_scripts/factory_ui b/src/scripts/mod_for_factory_scripts/factory_ui |
index 8b40199f82b8336d3c048ef4ab95904019983d89..35b8d72d6d03647384ca6348870089dbb5113eb1 100644 |
--- a/src/scripts/mod_for_factory_scripts/factory_ui |
+++ b/src/scripts/mod_for_factory_scripts/factory_ui |
@@ -35,12 +35,16 @@ import time |
def XXX_log(s): |
print >> sys.stderr, '--- XXX : ' + s |
+_ACTIVE = 'ACTIVE' |
+_PASSED = 'PASS' |
+_FAILED = 'FAIL' |
+_UNTESTED = 'UNTESTED' |
_LABEL_COLORS = { |
- 'active': gtk.gdk.color_parse('light goldenrod'), |
- 'passed': gtk.gdk.color_parse('pale green'), |
- 'failed': gtk.gdk.color_parse('tomato'), |
- 'untested': gtk.gdk.color_parse('dark slate grey')} |
+ _ACTIVE: gtk.gdk.color_parse('light goldenrod'), |
+ _PASSED: gtk.gdk.color_parse('pale green'), |
+ _FAILED: gtk.gdk.color_parse('tomato'), |
+ _UNTESTED: gtk.gdk.color_parse('dark slate grey')} |
_LABEL_EN_SIZE = (160, 35) |
_LABEL_EN_FONT = pango.FontDescription('courier new extra-condensed 16') |
@@ -50,10 +54,13 @@ _LABEL_T_SIZE = (30, 35) |
_LABEL_T_FONT = pango.FontDescription('courier new italic ultra-condensed 10') |
_LABEL_UNTESTED_FG = gtk.gdk.color_parse('grey40') |
_LABEL_TROUGH_COLOR = gtk.gdk.color_parse('grey20') |
+_LABEL_STATUS_SIZE = (140, 30) |
+_LABEL_STATUS_FONT = pango.FontDescription( |
+ 'courier new bold extra-condensed 16') |
_SEP_COLOR = gtk.gdk.color_parse('grey50') |
_BLACK = gtk.gdk.color_parse('black') |
_LIGHT_GREEN = gtk.gdk.color_parse('light green') |
- |
+_OTHER_LABEL_FONT = pango.FontDescription('courier new condensed 20') |
class console_proc: |
'''Display a progress log. Implemented by launching an borderless |
@@ -87,6 +94,11 @@ def control_send(x): |
print repr(x) |
sys.stdout.flush() |
+def control_send_target_test_update(test): |
+ XXX_log('ui send_target_test_update %s.%s_%s' % |
+ (test.formal_name, test.tag_prefix, test.count)) |
+ control_send((test.formal_name, test.tag_prefix, test.count)) |
+ |
# Capture keyboard events here for debugging -- under normal |
# circumstances, all keyboard events should be captured by executing |
@@ -97,85 +109,142 @@ def handle_key_release_event(_, event): |
return True |
-def update_label_status(test, status): |
- if status != 'untested': |
- test.label_box.modify_fg(gtk.STATE_NORMAL, _BLACK) |
- for label in test.label_list: |
- label.modify_fg(gtk.STATE_NORMAL, _BLACK) |
- test.label_box.modify_bg(gtk.STATE_NORMAL, _LABEL_COLORS[status]) |
- test.label_box.queue_draw() |
+class test_label_box(gtk.EventBox): |
+ |
+ def __init__(self, test): |
+ gtk.EventBox.__init__(self) |
+ label_en = gtk.Label(test.label_en) |
+ label_en.set_size_request(*_LABEL_EN_SIZE) |
+ label_en.modify_font(_LABEL_EN_FONT) |
+ label_en.set_alignment(0.8, 0.5) |
+ label_en.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) |
+ label_zw = gtk.Label(test.label_zw) |
+ label_zw.set_size_request(*_LABEL_ZW_SIZE) |
+ label_zw.modify_font(_LABEL_ZW_FONT) |
+ label_zw.set_alignment(0.2, 0.5) |
+ label_zw.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) |
+ label_t = gtk.Label('C-' + test.trigger) |
+ label_t.set_size_request(*_LABEL_T_SIZE) |
+ label_t.modify_font(_LABEL_T_FONT) |
+ label_t.set_alignment(0.5, 0.5) |
+ label_t.modify_fg(gtk.STATE_NORMAL, _BLACK) |
+ hbox = gtk.HBox() |
+ hbox.pack_start(label_en, False, False) |
+ hbox.pack_start(label_zw, False, False) |
+ hbox.pack_start(label_t, False, False) |
+ self.add(hbox) |
+ self.label_list = [label_en, label_zw] |
+ |
+ def update_status(self, status): |
+ if status != _UNTESTED: |
+ self.modify_fg(gtk.STATE_NORMAL, _BLACK) |
+ for label in self.label_list: |
+ label.modify_fg(gtk.STATE_NORMAL, _BLACK) |
+ self.modify_bg(gtk.STATE_NORMAL, _LABEL_COLORS[status]) |
+ self.queue_draw() |
+ |
+ |
+class subtest_label_box(gtk.EventBox): |
+ |
+ def __init__(self, test): |
+ gtk.EventBox.__init__(self) |
+ self.modify_bg(gtk.STATE_NORMAL, _BLACK) |
+ label_status = gtk.Label(_UNTESTED) |
+ label_status.set_size_request(*_LABEL_STATUS_SIZE) |
+ label_status.set_alignment(0, 0.5) |
+ label_status.modify_font(_LABEL_STATUS_FONT) |
+ label_status.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) |
+ label_en = gtk.Label(test.label_en) |
+ label_en.set_alignment(1, 0.5) |
+ label_en.modify_font(_LABEL_EN_FONT) |
+ label_en.modify_fg(gtk.STATE_NORMAL, _LIGHT_GREEN) |
+ label_zw = gtk.Label(test.label_zw) |
+ label_zw.set_alignment(1, 0.5) |
+ label_zw.modify_font(_LABEL_ZW_FONT) |
+ label_zw.modify_fg(gtk.STATE_NORMAL, _LIGHT_GREEN) |
+ label_sep = gtk.Label(' : ') |
+ label_sep.set_alignment(0.5, 0.5) |
+ label_sep.modify_font(_LABEL_EN_FONT) |
+ label_sep.modify_fg(gtk.STATE_NORMAL, _LIGHT_GREEN) |
+ hbox = gtk.HBox() |
+ hbox.pack_end(label_status, False, False) |
+ hbox.pack_end(label_sep, False, False) |
+ hbox.pack_end(label_zw, False, False) |
+ hbox.pack_end(label_en, False, False) |
+ self.add(hbox) |
+ self.label_status = label_status |
+ |
+ def update_status(self, status): |
+ if status != _UNTESTED: |
+ self.label_status.set_text(status) |
+ self.label_status.modify_fg(gtk.STATE_NORMAL, _LABEL_COLORS[status]) |
+ self.queue_draw() |
+ |
+ |
+class status_map(): |
+ |
+ def __init__(self): |
+ self.status_dict = {} |
+ |
+ def index(self, formal_name, tag_prefix): |
+ return '%s.%s' % (formal_name, tag_prefix) |
+ |
+ def lookup(self, formal_name, tag_prefix): |
+ return self.status_dict.setdefault( |
+ self.index(formal_name, tag_prefix), |
+ (_UNTESTED, 0)) |
+ |
+ def update(self, formal_name, tag_prefix, status, count): |
+ _, existing_count = self.lookup(formal_name, tag_prefix) |
+ if count > existing_count: |
+ index = self.index(formal_name, tag_prefix) |
+ self.status_dict[index] = (status, count) |
+ |
+ def get_subtest_status(self, test): |
+ map(self.set_test_status, test.automated_seq) |
+ sub_status_set = set(st.status for st in test.automated_seq) |
+ min_count = min([st.count for st in test.automated_seq]) |
+ max_count = max([st.count for st in test.automated_seq]) |
+ if len(sub_status_set) == 1: |
+ return (sub_status_set.pop(), max_count) |
+ if test.count > min_count: |
+ return (_ACTIVE, max_count) |
+ return (_FAILED, max_count) |
+ |
+ def set_test_status(self, test): |
+ status, count = ( |
+ test.automated_seq |
+ and self.get_subtest_status(test) |
+ or self.lookup(test.formal_name, test.tag_prefix)) |
+ status = test.count > count and _ACTIVE or status |
+ max_count = max(test.count, count) |
+ if test.status != status or test.count != max_count: |
+ XXX_log('status change for %s : %s/%s -> %s/%s' % |
+ (self.index(test.formal_name, test.tag_prefix), |
+ test.count, test.status, max_count, status)) |
+ test.status = status |
+ test.count = max_count |
+ test.label_box.update_status(status) |
def refresh_test_status(status_file_path, test_list): |
- result_dict = {} |
+ smap = status_map() |
with open(status_file_path) as file: |
for line in file: |
columns = line.split('\t') |
if len(columns) >= 8 and not columns[0] and not columns[1]: |
- result_state = columns[2] |
- full_name = columns[3] |
- result_dict[full_name] = result_state |
- for test in test_list: |
- full_name = '%s.%d' % (test.formal_name, test.count) |
- result_state = result_dict.get(full_name, None) |
- if result_state is None: |
- status = 'untested' |
- elif result_state == 'GOOD': |
- status = 'passed' |
- else: |
- status = 'failed' |
- if test.status != status: |
- XXX_log('status change for %s : %s -> %s' % |
- (test.label_en, test.status, status)) |
- test.status = status |
- update_label_status(test, status) |
+ status = columns[2] == 'GOOD' and _PASSED or _FAILED |
+ formal_name, _, tag = columns[3].rpartition('.') |
+ tag_prefix, _, count = tag.rpartition('_') |
+ count = int(count) |
+ smap.update(formal_name, tag_prefix, status, count) |
+ map(smap.set_test_status, test_list) |
-def select_active_test(test_list, remaining_tests_queue, |
- test_counters, trigger): |
- active_test = None |
- if trigger is not None: |
- trigger_dict = dict((test.trigger, test) for test in test_list) |
- active_test = trigger_dict.get(trigger, None) |
- if active_test in remaining_tests_queue: |
- remaining_tests_queue.remove(active_test) |
- if active_test is None: |
- active_test = remaining_tests_queue.pop() |
- count = test_counters[active_test.formal_name] |
- count += 1 |
- active_test.count = count |
- test_counters[active_test.formal_name] = count |
- update_label_status(active_test, 'active') |
- XXX_log('select_active_test %s.%d' % |
- (active_test.formal_name, active_test.count)) |
- return (active_test.label_en, active_test.count) |
- |
- |
-def make_test_label(test): |
- label_en = gtk.Label(test.label_en) |
- label_en.set_size_request(*_LABEL_EN_SIZE) |
- label_en.modify_font(_LABEL_EN_FONT) |
- label_en.set_alignment(0.8, 0.5) |
- label_en.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) |
- label_zw = gtk.Label(test.label_zw) |
- label_zw.set_size_request(*_LABEL_ZW_SIZE) |
- label_zw.modify_font(_LABEL_ZW_FONT) |
- label_zw.set_alignment(0.2, 0.5) |
- label_zw.modify_fg(gtk.STATE_NORMAL, _LABEL_UNTESTED_FG) |
- label_t = gtk.Label('C-' + test.trigger) |
- label_t.set_size_request(*_LABEL_T_SIZE) |
- label_t.modify_font(_LABEL_T_FONT) |
- label_t.set_alignment(0.5, 0.5) |
- label_t.modify_fg(gtk.STATE_NORMAL, _BLACK) |
- hbox = gtk.HBox() |
- hbox.pack_start(label_en, False, False) |
- hbox.pack_start(label_zw, False, False) |
- hbox.pack_start(label_t, False, False) |
- label_box = gtk.EventBox() |
- label_box.add(hbox) |
- test.label_box = label_box |
- test.label_list = [label_en, label_zw] |
- return label_box |
+def set_active_test(test): |
+ test.count += 1 |
+ test.label_box.update_status(_ACTIVE) |
+ control_send_target_test_update(test) |
def make_hsep(width=1): |
@@ -192,19 +261,23 @@ def make_vsep(width=1): |
return frame |
-def make_test_widget_box(): |
+def make_notest_label(): |
label = gtk.Label('no active test') |
- font = pango.FontDescription('courier new condensed 20') |
- label.modify_font(font) |
+ label.modify_font(_OTHER_LABEL_FONT) |
label.set_alignment(0.5, 0.5) |
label.modify_fg(gtk.STATE_NORMAL, _LIGHT_GREEN) |
box = gtk.EventBox() |
box.modify_bg(gtk.STATE_NORMAL, _BLACK) |
box.add(label) |
- align = gtk.Alignment(xalign=0.5, yalign=0.5) |
- align.set_size_request(-1, -1) |
- align.add(box) |
- return align |
+ return box |
+ |
+ |
+def make_automated_seq_widget(as_test): |
+ vbox = gtk.VBox() |
+ vbox.set_spacing(0) |
+ map(lambda st: vbox.pack_start(st.label_box, False, False), |
+ as_test.automated_seq) |
+ return vbox |
def main(): |
@@ -227,7 +300,11 @@ def main(): |
console_box.set_size_request(-1, 180) |
console_box.modify_bg(gtk.STATE_NORMAL, _BLACK) |
- test_widget_box = make_test_widget_box() |
+ notest_label = make_notest_label() |
+ |
+ test_widget_box = gtk.Alignment(xalign=0.5, yalign=0.5) |
+ test_widget_box.set_size_request(-1, -1) |
+ test_widget_box.add(notest_label) |
lhs_box = gtk.VBox() |
lhs_box.pack_end(console_box, False, False) |
@@ -252,8 +329,15 @@ def main(): |
for test in test_list: |
test.status = None |
- label = make_test_label(test) |
- label_trough.pack_start(label, False, False) |
+ test.count = 0 |
+ test.tag_prefix = test.trigger |
+ test.label_box = test_label_box(test) |
+ for subtest in test.automated_seq: |
+ subtest.status = None |
+ subtest.count = 0 |
+ subtest.tag_prefix = test.formal_name |
+ subtest.label_box = subtest_label_box(subtest) |
+ label_trough.pack_start(test.label_box, False, False) |
label_trough.pack_start(make_hsep(), False, False) |
window.add(base_box) |
@@ -265,15 +349,15 @@ def main(): |
XXX_log('test_widget_size = %s' % repr(test_widget_size)) |
control_send(test_widget_size) |
- # Use a common datastructure for counters to allow multiple tests |
- # to share the same formal name. |
- test_counters = dict((test.formal_name, 0) for test in test_list) |
- for test in test_list: |
- test.count = 0 |
+ trigger_dict = dict((test.trigger, test) for test in test_list) |
refresh_test_status(status_file_path, test_list) |
remaining_tests_queue = [x for x in reversed(test_list) |
- if test.status != 'passed'] |
+ if x.status == _UNTESTED] |
+ XXX_log('remaining_tests_queue = %s' % |
+ repr([x.label_en for x in remaining_tests_queue])) |
+ |
+ active_test = None |
gobject.io_add_watch(sys.stdin, gobject.IO_IN, stdin_callback) |
@@ -294,15 +378,44 @@ def main(): |
# (possibly None) to indicate how the next test should be selected. |
while remaining_tests_queue: |
- trigger = control_recv() |
- XXX_log('ui received trigger (%s)' % trigger) |
- active_test_name, count = select_active_test( |
- test_list, remaining_tests_queue, |
- test_counters, trigger) |
- control_send((active_test_name, count)) |
- gtk.main() |
- refresh_test_status(status_file_path, test_list) |
+ command, arg = control_recv() |
+ XXX_log('ui received command %s(%s)' % (command, arg)) |
+ if command == 'switch_to': |
+ active_test = trigger_dict.get(arg, None) |
+ if active_test in remaining_tests_queue: |
+ remaining_tests_queue.remove(active_test) |
+ set_active_test(active_test) |
+ elif command == 'next_test': |
+ active_test = remaining_tests_queue.pop() |
+ set_active_test(active_test) |
+ else: |
+ XXX_log('ui command unknown, exiting...') |
+ break |
+ if active_test.automated_seq: |
+ XXX_log('ui starting automated_seq') |
+ subtest_queue = [x for x in reversed(active_test.automated_seq)] |
+ test_widget_box.remove(notest_label) |
+ as_widget = make_automated_seq_widget(active_test) |
+ test_widget_box.add(as_widget) |
+ window.show_all() |
+ command = None |
+ while command != 'quit_automated_seq': |
+ active_subtest = subtest_queue.pop() |
+ active_subtest.label_box.update_status(_ACTIVE) |
+ gtk.main() |
+ command = control_recv() |
+ XXX_log('ui automated_seq step (%s)' % command) |
+ refresh_test_status(status_file_path, test_list) |
+ test_widget_box.queue_draw() |
+ test_widget_box.remove(as_widget) |
+ test_widget_box.add(notest_label) |
+ window.show_all() |
+ XXX_log('ui exiting automated_seq') |
+ else: |
+ gtk.main() |
+ refresh_test_status(status_file_path, test_list) |
+ # Tell the control process we are done. |
control_send((None, 0)) |
XXX_log('exiting ui') |