blob: c2c8a4d0ae76cbecaf9af75b8ee30e7a6473d274 [file] [log] [blame] [edit]
# Copyright (c) 2012 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.
"""Some utility classes and functions."""
import glob
import os
import re
import sys
import time
import common_util
import test_conf as conf
def get_display_name():
"""Return the display name."""
return ':0'
def get_screen_size():
"""Get the screen size using xwininfo."""
cmd = 'DISPLAY=:0 xwininfo -root'
wininfo = common_util.simple_system_output(cmd)
# the geometry string looks like:
# " -geometry 3840x1200+0+0"
geometry_pattern = re.compile('\s*-geometry\s*(\d+)x(\d+)+.*', re.I)
for line in wininfo.splitlines():
result = geometry_pattern.search(line)
if result:
width = int(result.group(1))
height = int(result.group(2))
return (width, height)
return None
def get_current_time_str():
"""Get the string of current time."""
time_format = '%Y%m%d_%H%M%S'
return time.strftime(time_format, time.gmtime())
def get_board():
"""Get board of the Chromebook machine."""
with open('/etc/lsb-release') as lsb:
context = lsb.read()
board = None
if context is not None:
for line in context.splitlines():
if line.startswith('CHROMEOS_RELEASE_BOARD'):
board_str = line.split('=')[1]
if '-' in board_str:
board = board_str.split('-')[1]
elif '_' in board_str:
board = board_str.split('_')[1]
else:
board = board_str
# Some boards, e.g. alex, may have board name as alex32
board = re.search('(\D+)\d*', board, re.I).group(1)
break
return board
def get_board_from_filename(filename):
"""Get the board name from a given string which is usually a log file.
A log file looks like:
touch_firmware_report-lumpy-fw_11.27-complete-20130610_150540.log
@param filename: the filename used to extract the board
"""
pieces = filename.split('-')
return pieces[1] if len(pieces) >= 2 else None
def get_board_from_directory(directory):
"""Get the board name from the log in the replay directory.
@param directory: the log directory
"""
log_files = glob.glob(os.path.join(conf.log_root_dir, directory, '*.log'))
for log_file in log_files:
board = get_board_from_filename(os.path.basename(log_file))
if board:
return board
return None
def get_cpu():
"""Get the processor of the machine."""
return common_util.simple_system_output('uname -m')
def install_pygtk():
"""A temporary dirty hack of installing pygtk related packages."""
pygtk_dict = {'x86_64': ['pygtk_x86_64.tbz2', 'lib64'],
'i686': ['pygtk_x86_32.tbz2', 'lib'],
'armv7l': ['pygtk_armv7l.tbz2', 'lib'],
}
pygtk_info = pygtk_dict.get(get_cpu().lower())
if get_board() is None:
print 'This does not look like a chromebook.'
elif pygtk_info:
cmd_remount = 'mount -o remount,rw /'
if common_util.simple_system(cmd_remount) == 0:
pygtk_tarball, lib_path = pygtk_info
cmd_untar = 'tar -jxf pygtk/%s -C /' % pygtk_tarball
if common_util.simple_system(cmd_untar) == 0:
# Need to add the gtk path manually. Otherwise, the path
# may not be in the sys.path for the first time when the
# tarball is extracted.
gtk_path = ('/usr/local/%s/python2.7/site-packages/gtk-2.0' %
lib_path)
sys.path.append(gtk_path)
print 'Successful installation of pygtk.'
return True
else:
print 'Error: Failed to install pygtk.'
else:
print 'Failed to remount. Have you removed the write protect?'
else:
print 'The pygtk is only supported for %s so far.' % pygtk_dict.keys()
print 'The other cpus will be supported on demand.'
print 'The plan is to remove gtk totally and upgrade to Chrome browser.'
return False
def get_fw_and_date(filename):
"""Get the firmware version and the test date from a log directory
or a log file.
An example html filename looks like
'touch_firmware_report-link-fw_1.0.170-manual-20130426_064849.log'
return (fw_1.0.170, 20130426_064849)
An example log directory looks like
'20130422_020631-fw_1.0.170-manual'
return (fw_1.0.170, 20130422_020631)
"""
# The firmware could be fw_1.0.170 or fw_1.0.AA which always comes with
# 'fw_' as its prefix. The character '-' is used to separate components
# in the filename.
result = re.search('-(%s[^-]+?)-' % conf.fw_prefix, filename)
fw = result.group(1) if result else None
result = re.search('(\d{8}_\d{6})[-.]', filename)
date = result.group(1) if result else None
return (fw, date)
def create_log_dir(firmware_version, mode):
"""Create a directory to save the report and device event files."""
dir_basename = conf.filename.sep.join([get_current_time_str(),
conf.fw_prefix + firmware_version,
mode])
log_root_dir = conf.log_root_dir
log_dir = os.path.join(log_root_dir, dir_basename)
latest_symlink = os.path.join(log_root_dir, 'latest')
# Create the log directory.
try:
os.makedirs(log_dir)
except OSError, e:
print 'Error in create the directory (%s): %s' % (log_dir, e)
sys.exit(1)
# Set up the latest symbolic link to the newly created log directory.
try:
if os.path.islink(latest_symlink):
os.remove(latest_symlink)
os.symlink(log_dir, latest_symlink)
except OSError, e:
print 'Error in setup latest symlink (%s): %s' % (latest_symlink, e)
sys.exit(1)
return log_dir
def stop_power_management():
"""Stop the power daemon management."""
ret_d = common_util.simple_system('stop -q powerd')
if ret_d:
print 'Error in stopping powerd.'
print 'The screen may dim during the test.'
def start_power_management():
"""Start the power daemon management."""
ret_d = common_util.simple_system('start -q powerd')
if ret_d:
print 'Error in starting powerd.'
print 'The screen may not go into suspend mode.'
print 'If this is a problem, you could reboot the machine.'
class GestureList:
"""A class defines the gesture list."""
def __init__(self, gesture_names=None):
self.gesture_names = (gesture_names if gesture_names
else conf.gesture_names_complete)
def get_gesture_list(self, key=None):
"""Get the list of Gesture objects based on the gesture names."""
gesture_dict = conf.get_gesture_dict()
gesture_list = []
for name in self.gesture_names:
gesture = gesture_dict.get(name)
if gesture is None:
msg = 'Error: the gesture "%s" is not defined in the config.'
print msg % name
return []
gesture_list.append(gesture)
return sorted(gesture_list, key=key) if key else gesture_list
class Output:
"""A class to handle outputs to the window and to the report."""
def __init__(self, log_dir, report_name, win, report_html):
self.log_dir = log_dir
self.report_name = report_name
self.report = open(report_name, 'w')
self.win = win
self.prefix_space = ' ' * 4
self.msg = None
self.report_html = report_html
def __del__(self):
self.stop()
def stop(self):
"""Close the report file and print it on stdout."""
self.report.close()
with open(self.report_name) as f:
for line in f.read().splitlines():
print line
report_msg = '\n*** This test report is saved in the file: %s\n'
print report_msg % self.report_name
def get_prefix_space(self):
"""Get the prefix space when printing the report."""
return self.prefix_space
def print_report_line(self, msg):
"""Print the line with proper indentation."""
self.report.write(self.prefix_space + str(msg) + os.linesep)
def print_window(self, msg):
"""Print the message to the result window."""
if type(msg) is list:
msg = os.linesep.join(msg)
self.win.set_result(msg)
print msg
def _print_report(self, msg):
"""Print the message to the report."""
if type(msg) is list:
for line in msg:
self.print_report_line(line)
else:
self.print_report_line(msg)
def buffer_report(self, msg):
"""Buffer the message and print it later if not over-written.
Usage of the method: the validator test result of a gesture may
be discarded because the user chooses to re-perform the gesture
again. So it should be able to over-write the message.
"""
self.msg = msg
def flush_report(self):
"""Print the buffered message if any."""
if self.msg:
self._print_report(self.msg)
self.msg = None
def print_report(self, msg):
"""Print the message to the report."""
# Print any buffered message first.
self.flush_report()
# Print this incoming message
self._print_report(msg)
def print_all(self, msg):
"""Print the message to both report and to the window."""
self.print_window(msg)
self.buffer_report(msg)
class ScreenShot:
"""Handle screen shot."""
def __init__(self, geometry_str):
self.geometry_str = geometry_str
environment_str = 'DISPLAY=:0.0 XAUTHORITY=/home/chronos/.Xauthority '
dump_util = '/usr/local/bin/import -quality 20'
self.dump_window_format = ' '.join([environment_str, dump_util,
'-window %s %s.png'])
self.dump_root_format = ' '.join([environment_str, dump_util,
'-window root -crop %s %s.png'])
self.get_id_cmd = 'DISPLAY=:0 xwininfo -root -tree'
def dump_window(self, filename):
"""Dump the screenshot of a window to the specified file name."""
win_id = self._get_win_id()
if win_id:
dump_cmd = self.dump_window_format % (win_id, filename)
common_util.simple_system(dump_cmd)
else:
print 'Warning: cannot get the window id.'
def dump_root(self, filename):
"""Dump the screenshot of root to the specified file name."""
dump_cmd = self.dump_root_format % (self.geometry_str, filename)
common_util.simple_system(dump_cmd)
def _get_win_id(self):
"""Get the window ID based on the characteristic string."""
result = common_util.simple_system_output(self.get_id_cmd)
for line in result.splitlines():
if self.geometry_str in line:
return line.split()[0].strip()
return None