# Copyright 2007 Google Inc. Released under the GPL v2
#
# Eric Li <ericli@google.com>
import logging, os, pickle, re, sys
import common
from autotest_lib.client.bin import job as client_job
from autotest_lib.client.common_lib import base_job
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import logging_manager
from autotest_lib.client.common_lib import packages
class setup_job(client_job.job):
"""
setup_job is a job which runs client test setup() method at server side.
This job is used to pre-setup client tests when development toolchain is not
available at client.
"""
def __init__(self, options):
"""
Since setup_job is a client job but run on a server, it takes no control
file as input. So client_job.__init__ is by-passed.
@param options: an object passed in from command line OptionParser.
See all options defined on client/bin/autotest.
"""
base_job.base_job.__init__(self, options=options)
self._cleanup_debugdir_files()
self._cleanup_results_dir()
self.machine_dict_list = [{'hostname' : options.hostname}]
# Client side tests should always run the same whether or not they are
# running in the lab.
self.in_lab = False
self.pkgmgr = packages.PackageManager(
self.autodir, run_function_dargs={'timeout':3600})
def init_test(options, testdir):
"""
Instantiate a client test object from a given test directory.
@param options Command line options passed in to instantiate a setup_job
which associates with this test.
@param testdir The test directory.
@returns A test object or None if failed to instantiate.
"""
locals_dict = locals().copy()
globals_dict = globals().copy()
locals_dict['testdir'] = testdir
job = setup_job(options=options)
locals_dict['job'] = job
test_name = os.path.split(testdir)[-1]
outputdir = os.path.join(job.resultdir, test_name)
try:
os.makedirs(outputdir)
except OSError:
pass
locals_dict['outputdir'] = outputdir
sys.path.insert(0, testdir)
client_test = None
try:
try:
import_stmt = 'import %s' % test_name
init_stmt = ('auto_test = %s.%s(job, testdir, outputdir)' %
(test_name, test_name))
exec import_stmt + '\n' + init_stmt in locals_dict, globals_dict
client_test = globals_dict['auto_test']
except ImportError, e:
# skips error if test is control file without python test
if re.search(test_name, str(e)):
pass
# give the user a warning if there is an import error.
else:
logging.exception('%s import error: %s. Skipping %s' %
(test_name, e, test_name))
except Exception, e:
# Log other errors (e.g., syntax errors) and collect the test.
logging.exception("%s: %s", test_name, e)
finally:
sys.path.pop(0) # pop up testbindir
return client_test
def load_all_client_tests(options):
"""
Load and instantiate all client tests.
This function is inspired from runtest() on client/common_lib/test.py.
@param options: an object passed in from command line OptionParser.
See all options defined on client/bin/autotest.
@return a tuple containing the list of all instantiated tests and
a list of tests that failed to instantiate.
"""
local_namespace = locals().copy()
global_namespace = globals().copy()
all_tests = []
broken_tests = []
for test_base_dir in ['tests', 'site_tests']:
testdir = os.path.join(os.environ['AUTODIR'], test_base_dir)
for test_name in sorted(os.listdir(testdir)):
client_test = init_test(options, os.path.join(testdir, test_name))
if client_test:
all_tests.append(client_test)
else:
broken_tests.append(test_name)
return all_tests, broken_tests
def setup_test(client_test):
"""
Direct invoke test.setup() method.
@returns A boolean to represent success or not.
"""
# TODO: check if its already build. .version? hash?
test_name = client_test.__class__.__name__
cwd = os.getcwd()
good_setup = False
try:
try:
outputdir = os.path.join(client_test.job.resultdir, test_name)
try:
os.makedirs(outputdir)
os.chdir(outputdir)
except OSError:
pass
logging.info('setup %s.' % test_name)
client_test.setup()
# Touch .version file under src to prevent further setup on client
# host. See client/common_lib/utils.py update_version()
if os.path.exists(client_test.srcdir):
versionfile = os.path.join(client_test.srcdir, '.version')
pickle.dump(client_test.version, open(versionfile, 'w'))
good_setup = True
except Exception, err:
logging.error(err)
raise error.AutoservError('Failed to build client test %s on '
'server.' % test_name)
finally:
# back to original working dir
os.chdir(cwd)
return good_setup
def setup_tests(options):
"""
Load and instantiate all client tests.
This function is inspired from runtest() on client/common_lib/test.py.
@param options: an object passed in from command line OptionParser.
See all options defined on client/bin/autotest.
"""
assert options.client_test_setup, 'Specify prebuild client tests on the ' \
'command line.'
requested_tests = options.client_test_setup.split(',')
candidates, broken_tests = load_all_client_tests(options)
failed_tests = []
if 'all' in requested_tests:
need_to_setup = candidates
failed_tests += broken_tests
else:
need_to_setup = []
for candidate in candidates:
if candidate.__class__.__name__ in requested_tests:
need_to_setup.append(candidate)
for broken_test in broken_tests:
if broken_test in requested_tests:
failed_tests.append(broken_test)
if need_to_setup:
cwd = os.getcwd()
os.chdir(need_to_setup[0].job.clientdir)
os.system('tools/make_clean')
os.chdir(cwd)
elif not failed_tests:
logging.error('### No test setup candidates ###')
raise error.AutoservError('No test setup candidates.')
for client_test in need_to_setup:
good_setup = setup_test(client_test)
if not good_setup:
failed_tests.append(client_test.__class__.__name__)
logging.info('############################# SUMMARY '
'#############################')
# Print out tests that failed
if failed_tests:
logging.info('Finished setup -- The following tests failed')
for failed_test in failed_tests:
logging.info(failed_test)
else:
logging.info('Finished setup -- All tests built successfully')
logging.info('######################### END SUMMARY '
'##############################')
if failed_tests:
raise error.AutoservError('Finished setup with errors.')