Move factory UI files to autotest repo.

Review URL: http://codereview.chromium.org/2825014
This commit is contained in:
Tammo Spalink 2010-06-22 16:09:04 +08:00
parent 75dc6c7845
commit c75941a05d
4 changed files with 2 additions and 472 deletions

View File

@ -49,11 +49,11 @@ stop on starting halt or starting reboot
script
cd /usr/local/autotest
eval \$(./factory_startx.sh)
eval \$(./deps/factory/startx.sh)
date >> /var/log/factory.log
if [ ! -e factory_started ]; then
touch factory_started
cp -f site_tests/suite_Factory/control.ui control
cp -f site_tests/suite_Factory/control .
./bin/autotest control >> /var/log/factory.log 2>&1
else
./tools/autotest >> /var/log/factory.log 2>&1

View File

@ -6,14 +6,6 @@
echo "Configure autotest setting."
SCRIPT_DIR="${GCLIENT_ROOT}/src/scripts/mod_for_factory_scripts/"
AUTOTEST_DIR="${ROOT_FS_DIR}/usr/local/autotest/"
cp "${SCRIPT_DIR}/factory_ui" "${AUTOTEST_DIR}"
chmod +x "${AUTOTEST_DIR}/factory_ui"
cp "${SCRIPT_DIR}/factory_startx.sh" "${AUTOTEST_DIR}"
chmod +x "${AUTOTEST_DIR}/factory_startx.sh"
GLOBAL_CONFIG="${ROOT_FS_DIR}/usr/local/autotest/global_config.ini"
if [ -f "${GLOBAL_CONFIG}" ]; then

View File

@ -1,31 +0,0 @@
#!/bin/sh
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
XAUTH=/usr/bin/xauth
XAUTH_FILE="/var/run/factory_ui.auth"
SERVER_READY=
DISPLAY=":0"
user1_handler () {
echo "X server ready..." 1>&2
SERVER_READY=y
}
trap user1_handler USR1
MCOOKIE=$(head -c 8 /dev/urandom | openssl md5)
${XAUTH} -q -f ${XAUTH_FILE} add ${DISPLAY} . ${MCOOKIE}
/sbin/xstart.sh ${XAUTH_FILE} &
while [ -z ${SERVER_READY} ]; do
sleep .1
done
/sbin/initctl emit factory-ui-started
cat /proc/uptime > /tmp/uptime-x-started
echo "DISPLAY=${DISPLAY}; export DISPLAY"
echo "XAUTHORITY=${XAUTH_FILE}; export XAUTHORITY"

View File

@ -1,431 +0,0 @@
#!/usr/bin/python
#
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# DESCRIPTION :
#
# This UI is intended to be used by the factory autotest suite to
# provide factory operators feedback on test status and control over
# execution order.
#
# In short, the UI is composed of a 'console' panel on the bottom of
# the screen which displays the autotest log, and there is also a
# 'test list' panel on the right hand side of the screen. The
# majority of the screen is dedicated to tests, which are executed in
# seperate processes, but instructed to display their own UIs in this
# dedicated area whenever possible. Tests in the test list are
# executed in order by default, but can be activated on demand via
# associated keyboard shortcuts (triggers). As tests are run, their
# status is color-indicated to the operator -- greyed out means
# untested, yellow means active, green passed and red failed.
import gobject
import gtk
import os
import pango
import subprocess
import sys
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')}
_LABEL_EN_SIZE = (160, 35)
_LABEL_EN_FONT = pango.FontDescription('courier new extra-condensed 16')
_LABEL_ZW_SIZE = (70, 35)
_LABEL_ZW_FONT = pango.FontDescription('normal 12')
_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
xterm at a strategic location, and running tail against the log.'''
def __init__(self, allocation, log_file_path):
xterm_coords = '135x14+%d+%d' % (allocation.x, allocation.y)
XXX_log('xterm_coords = %s' % xterm_coords)
xterm_cmd = ('xterm --geometry %s -bw 0 -e ' % xterm_coords +
'tail -f %s' % log_file_path)
self._proc = subprocess.Popen(xterm_cmd.split())
def __del__(self):
XXX_log('console_proc __del__')
self._proc.kill()
# Routines to communicate with the autotest control file, using python
# expressions. The stdin_callback assures notification for any new
# messages.
def stdin_callback(s, c):
XXX_log('stdin_callback, quitting gtk main')
gtk.main_quit()
return True
def control_recv():
return eval(sys.stdin.readline().rstrip())
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
# tests, and hence this should not be called.
def handle_key_release_event(_, event):
XXX_log('base ui key event (%s)' % event.keyval)
return True
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):
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]:
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 set_active_test(test):
test.count += 1
test.label_box.update_status(_ACTIVE)
control_send_target_test_update(test)
def make_hsep(width=1):
frame = gtk.EventBox()
frame.set_size_request(-1, width)
frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR)
return frame
def make_vsep(width=1):
frame = gtk.EventBox()
frame.set_size_request(width, -1)
frame.modify_bg(gtk.STATE_NORMAL, _SEP_COLOR)
return frame
def make_notest_label():
label = gtk.Label('no active test')
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)
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():
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.connect('destroy', lambda _: gtk.main_quit())
window.modify_bg(gtk.STATE_NORMAL, _BLACK)
screen = window.get_screen()
screen_size = (screen.get_width(), screen.get_height())
window.set_size_request(*screen_size)
label_trough = gtk.VBox()
label_trough.set_spacing(0)
rhs_box = gtk.EventBox()
rhs_box.modify_bg(gtk.STATE_NORMAL, _LABEL_TROUGH_COLOR)
rhs_box.add(label_trough)
console_box = gtk.EventBox()
console_box.set_size_request(-1, 180)
console_box.modify_bg(gtk.STATE_NORMAL, _BLACK)
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)
lhs_box.pack_start(test_widget_box)
lhs_box.pack_start(make_hsep(3), False, False)
base_box = gtk.HBox()
base_box.pack_end(rhs_box, False, False)
base_box.pack_end(make_vsep(3), False, False)
base_box.pack_start(lhs_box)
window.connect('key-release-event', handle_key_release_event)
window.add_events(gtk.gdk.KEY_RELEASE_MASK)
# On startup, get general configuration data from the autotest
# control program, specifically the list of tests to run (in
# order) and some filenames.
XXX_log('pulling control info')
test_list = control_recv()
status_file_path = control_recv()
log_file_path = control_recv()
for test in test_list:
test.status = None
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)
window.show_all()
test_widget_allocation = test_widget_box.get_allocation()
test_widget_size = (test_widget_allocation.width,
test_widget_allocation.height)
XXX_log('test_widget_size = %s' % repr(test_widget_size))
control_send(test_widget_size)
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 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)
console = console_proc(console_box.get_allocation(), log_file_path)
XXX_log('finished ui setup')
# Test selection is driven either by triggers or by the
# remaining_tests_queue. If a trigger was seen, explicitly run
# the corresponding test. Otherwise choose the next test from the
# queue. Tests are removed from the queue as they are run,
# regarless of the outcome. Tests that are interrupted by trigger
# are treated as having failed.
#
# Iterations in the main loop here are driven by data availability
# on stdin, which is used to communicate with the autotest control
# program. On each step through the loop, a trigger is received
# (possibly None) to indicate how the next test should be selected.
while remaining_tests_queue:
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')
if __name__ == '__main__':
# In global scope, get the test_data class description from the
# control program -- this allows a convenient single point of
# definition for this class.
test_data_class_def = control_recv()
exec(test_data_class_def)
main()