| # 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.') |