blob: 99049ca37547694548c66f52f651ce7e83014285 [file] [log] [blame]
# Copyright (c) 2011 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.
''' Autotest program for verifying trackpad X level driver '''
import glob
import logging
import os
import time
from autotest_lib.client.bin import test, utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros import cros_ui
from trackpad_device import TrackpadDevice
from trackpad_util import read_trackpad_test_conf, get_prefix
from Xcapture import Xcapture
from Xcheck import Xcheck
class TrackpadData:
''' An empty class to hold global trackpad test data for communication
between threads
'''
pass
''' tdata: trackpad data as a global variable used between threads
(1) The main thread runs in the hardware_Trackpad class will derive the test
result through Xcheck class. The test result is stored in tdata.
It requires read/write access to tdata.
(2) A second thread will launch a HTTP server that communicates with a
chrome extension on the target machine to display the test result
on the fly during the test procedure. When the result of a gesture file
test has been derived, it is sent to the browser for display.
Note: it is not required to use mutex to protect the global tdata for two
reasons:
- tdata will be accessed sequentially between the two threads.
- The main thread is a writer, and the HTTP server thread is a reader.
No lock is needed in this case.
'''
tdata = TrackpadData()
class hardware_Trackpad(test.test):
''' Play back device packets through the trackpad device. Capture the
resultant X events. Analyze whether the X events meet the criteria
of the functionality.
'''
version = 1
def run_once(self):
global tdata
tdata.file_basename = None
tdata.chrome_request = 0
tdata.report_finished = False
# Get functionality_list, and gesture_files_path from config file
local_path = self.autodir + '/tests/hardware_Trackpad'
functionality_list = read_trackpad_test_conf('functionality_list',
local_path)
gesture_files_path_conf = read_trackpad_test_conf('gesture_files_path',
local_path)
gesture_files_path = os.path.join(local_path, gesture_files_path_conf)
logging.info('Path of trackpad gesture files: %s' % gesture_files_path)
# Initialization of statistics
tdata.num_wrong_file_name = 0
tdata.num_files_tested = {}
tdata.tot_fail_count = 0
tdata.tot_num_files_tested = 0
tdata.fail_count = dict([(tp_func.name, 0)
for tp_func in functionality_list])
logging.info('')
logging.info('*** hardware_Trackpad autotest is started ***')
# Start Trackpad Input Device
self.tp_device = TrackpadDevice(local_path)
# Get an instance of AutoX to handle X related issues
autox = cros_ui.get_autox()
# Start X events capture
self.xcapture = Xcapture(error, local_path, autox)
# Initialize X events Check
self.xcheck = Xcheck(self.tp_device, local_path)
# Processing every functionality in functionality_list
# An example functionality is 'any_finger_click'
for tdata.func in functionality_list:
# If this function is not enabled in configuration file, skip it.
if not tdata.func.enabled:
continue;
logging.info('\n')
logging.info('Functionality: %s (Area: %s)' %
(tdata.func.name, tdata.func.area[1]))
tdata.num_files_tested[tdata.func.name] = 0
# Some cases of specifying gesture files in the configuration file:
# Case 1:
# If gesture files are set to None in this functionality, skip it.
# It looks as:
# files=None, or
# files=(None,),
#
# Case 2:
# '*' means all files starting with the functionality name
# Its setting in the configuration file looks as
# files='*', or
# files=('*',),
#
# Case 3:
# In other case, gesture files could be set as:
# ('any_finger_click.l1-*', 'any_finger_click.r*')
if tdata.func.files is None or tdata.func.files.count(None) > 0:
logging.info(' Gesture files is set to None. Skipped.')
continue
elif tdata.func.files == '*' or tdata.func.files.count('*') > 0:
group_name_list = ('*',)
else:
group_name_list = tdata.func.files
# A group name can be '*', or something looks like
# 'any_finger_click.l1-*', or
# 'any_finger_click.r*'), etc.
for group_name in group_name_list:
# prefix is the area name as default
tdata.prefix = get_prefix(tdata.func)
if tdata.prefix is not None:
# E.g., prefix = 'click-'
prefix = tdata.prefix + '-'
group_path = os.path.join(gesture_files_path, prefix)
if group_name == '*':
# E.g., group_path = '.../click-any_finger_click'
group_path = group_path + tdata.func.name
# Two possibilities of the gesture_file_group:
# 1. '.../click-any_finger_click.*':
# variations exists (subname is not None)
# 2. '.../click-any_finger_click-*': no variations
# no variations (subname is None)
# Note: attributes are separated by dash ('-')
# variations are separated by dot ('.')
gesture_file_group = (glob.glob(group_path + '.*') +
glob.glob(group_path + '-*'))
else:
group_path = group_path + group_name
gesture_file_group = glob.glob(group_path)
# Process each specific gesture_file now.
for gesture_file in gesture_file_group:
# Every gesture file name should start with the correct
# functionality name, because we use the functionality to
# determine the test criteria for the file. Otherwise,
# a warning message is shown.
tdata.file_basename = os.path.basename(gesture_file)
start_flag0 = tdata.file_basename.startswith(
tdata.func.name)
start_flag1 = tdata.file_basename.split('-')[1].startswith(
tdata.func.name)
if (tdata.prefix is None and not start_flag0) or \
(tdata.prefix is not None and not start_flag1):
warn_msg = 'The gesture file does not start with ' + \
'correct functionality: %s'
logging.warning(warn_msg % gesture_file)
tdata.num_wrong_file_name += 1
gesture_file_path = os.path.join(gesture_files_path,
gesture_file)
logging.info('')
logging.info(' gesture file: %s' % tdata.file_basename)
# Start X events capture
self.xcapture.start(tdata.file_basename)
# Play back the gesture file
self.tp_device.playback(gesture_file_path)
# Wait until there are no more incoming X events.
normal_timeout_flag = self.xcapture.wait()
# Stop X events capture
self.xcapture.stop()
# Check X events
tdata.result = self.xcheck.run(tdata.func, tdata,
self.xcapture.read()) and \
normal_timeout_flag
# Update statistics
tdata.num_files_tested[tdata.func.name] += 1
tdata.tot_num_files_tested += 1
if not tdata.result:
tdata.fail_count[tdata.func.name] += 1
tdata.tot_fail_count += 1
# Terminate X event capture process
self.xcapture.terminate()
# Logging test summary
logging.info('\n')
tot_pass_count = tdata.tot_num_files_tested - tdata.tot_fail_count
logging.info('*** Total number of (passed / tested) files: (%d / %d) '
'***' % (tot_pass_count, tdata.tot_num_files_tested))
area_name = None
for tp_func in functionality_list:
func_name = tp_func.name
if tp_func.area[0] != area_name:
area_name = tp_func.area[0]
logging.info(' Area: %s' % area_name)
test_count = tdata.num_files_tested[func_name]
fail_count = tdata.fail_count[func_name]
pass_count = test_count - fail_count
if test_count > 0:
pass_rate_str = '%3.0f%%' % (100.0 * pass_count / test_count)
count_str = '(%d / %d)' % (pass_count, test_count)
else:
pass_rate_str = ' '
count_str = ' '
func_msg = ' {0:<25}: {1:4s} {2:9s} passed.'
logging.info(func_msg.format(func_name, pass_rate_str, count_str))
logging.info('\n')
# Raise error.TestFail if there is any test failed.
if tdata.tot_fail_count > 0:
fail_str = 'Total number of failed files: %d'
raise error.TestFail(fail_str % tdata.tot_fail_count)