Home | History | Annotate | Download | only in bin
      1 # Copyright 2007 Google Inc. Released under the GPL v2
      2 #
      3 # Eric Li <ericli (at] google.com>
      4 
      5 import logging, os, pickle, re, sys
      6 import common
      7 
      8 from autotest_lib.client.bin import job as client_job
      9 from autotest_lib.client.common_lib import base_job
     10 from autotest_lib.client.common_lib import error
     11 from autotest_lib.client.common_lib import logging_manager
     12 from autotest_lib.client.common_lib import packages
     13 
     14 
     15 class setup_job(client_job.job):
     16     """
     17     setup_job is a job which runs client test setup() method at server side.
     18 
     19     This job is used to pre-setup client tests when development toolchain is not
     20     available at client.
     21     """
     22 
     23     def __init__(self, options):
     24         """
     25         Since setup_job is a client job but run on a server, it takes no control
     26         file as input. So client_job.__init__ is by-passed.
     27 
     28         @param options: an object passed in from command line OptionParser.
     29                         See all options defined on client/bin/autotest.
     30         """
     31         base_job.base_job.__init__(self, options=options)
     32         self._cleanup_debugdir_files()
     33         self._cleanup_results_dir()
     34         self.machine_dict_list = [{'hostname' : options.hostname}]
     35         # Client side tests should always run the same whether or not they are
     36         # running in the lab.
     37         self.in_lab = False
     38         self.pkgmgr = packages.PackageManager(
     39             self.autodir, run_function_dargs={'timeout':3600})
     40 
     41 
     42 def init_test(options, testdir):
     43     """
     44     Instantiate a client test object from a given test directory.
     45 
     46     @param options Command line options passed in to instantiate a setup_job
     47                    which associates with this test.
     48     @param testdir The test directory.
     49     @returns A test object or None if failed to instantiate.
     50     """
     51 
     52     locals_dict = locals().copy()
     53     globals_dict = globals().copy()
     54 
     55     locals_dict['testdir'] = testdir
     56 
     57     job = setup_job(options=options)
     58     locals_dict['job'] = job
     59 
     60     test_name = os.path.split(testdir)[-1]
     61     outputdir = os.path.join(job.resultdir, test_name)
     62     try:
     63         os.makedirs(outputdir)
     64     except OSError:
     65         pass
     66     locals_dict['outputdir'] = outputdir
     67 
     68     sys.path.insert(0, testdir)
     69     client_test = None
     70     try:
     71         try:
     72             import_stmt = 'import %s' % test_name
     73             init_stmt = ('auto_test = %s.%s(job, testdir, outputdir)' %
     74                          (test_name, test_name))
     75             exec import_stmt + '\n' + init_stmt in locals_dict, globals_dict
     76             client_test = globals_dict['auto_test']
     77         except ImportError, e:
     78             # skips error if test is control file without python test
     79             if re.search(test_name, str(e)):
     80                 pass
     81             # give the user a warning if there is an import error.
     82             else:
     83                 logging.exception('%s import error: %s.  Skipping %s' %
     84                               (test_name, e, test_name))
     85         except Exception, e:
     86             # Log other errors (e.g., syntax errors) and collect the test.
     87             logging.exception("%s: %s", test_name, e)
     88     finally:
     89         sys.path.pop(0) # pop up testbindir
     90     return client_test
     91 
     92 
     93 def load_all_client_tests(options):
     94     """
     95     Load and instantiate all client tests.
     96 
     97     This function is inspired from runtest() on client/common_lib/test.py.
     98 
     99     @param options: an object passed in from command line OptionParser.
    100                     See all options defined on client/bin/autotest.
    101 
    102     @return a tuple containing the list of all instantiated tests and
    103             a list of tests that failed to instantiate.
    104     """
    105 
    106     local_namespace = locals().copy()
    107     global_namespace = globals().copy()
    108 
    109     all_tests = []
    110     broken_tests = []
    111     for test_base_dir in ['tests', 'site_tests']:
    112         testdir = os.path.join(os.environ['AUTODIR'], test_base_dir)
    113         for test_name in sorted(os.listdir(testdir)):
    114             client_test = init_test(options, os.path.join(testdir, test_name))
    115             if client_test:
    116                 all_tests.append(client_test)
    117             else:
    118                 broken_tests.append(test_name)
    119     return all_tests, broken_tests
    120 
    121 
    122 def setup_test(client_test):
    123     """
    124     Direct invoke test.setup() method.
    125 
    126     @returns A boolean to represent success or not.
    127     """
    128 
    129     # TODO: check if its already build. .version? hash?
    130     test_name = client_test.__class__.__name__
    131     cwd = os.getcwd()
    132     good_setup = False
    133     try:
    134         try:
    135             outputdir = os.path.join(client_test.job.resultdir, test_name)
    136             try:
    137                 os.makedirs(outputdir)
    138                 os.chdir(outputdir)
    139             except OSError:
    140                 pass
    141             logging.info('setup %s.' % test_name)
    142             client_test.setup()
    143 
    144             # Touch .version file under src to prevent further setup on client
    145             # host. See client/common_lib/utils.py update_version()
    146             if os.path.exists(client_test.srcdir):
    147                 versionfile = os.path.join(client_test.srcdir, '.version')
    148                 pickle.dump(client_test.version, open(versionfile, 'w'))
    149             good_setup = True
    150         except Exception, err:
    151             logging.error(err)
    152             raise error.AutoservError('Failed to build client test %s on '
    153                                       'server.' % test_name)
    154     finally:
    155         # back to original working dir
    156         os.chdir(cwd)
    157     return good_setup
    158 
    159 
    160 def setup_tests(options):
    161     """
    162     Load and instantiate all client tests.
    163 
    164     This function is inspired from runtest() on client/common_lib/test.py.
    165 
    166     @param options: an object passed in from command line OptionParser.
    167                     See all options defined on client/bin/autotest.
    168     """
    169 
    170     assert options.client_test_setup, 'Specify prebuild client tests on the ' \
    171                                       'command line.'
    172 
    173     requested_tests = options.client_test_setup.split(',')
    174     candidates, broken_tests = load_all_client_tests(options)
    175 
    176     failed_tests = []
    177     if 'all' in requested_tests:
    178         need_to_setup = candidates
    179         failed_tests += broken_tests
    180     else:
    181         need_to_setup = []
    182         for candidate in candidates:
    183             if candidate.__class__.__name__ in requested_tests:
    184                 need_to_setup.append(candidate)
    185         for broken_test in broken_tests:
    186             if broken_test in requested_tests:
    187                 failed_tests.append(broken_test)
    188 
    189     if need_to_setup:
    190         cwd = os.getcwd()
    191         os.chdir(need_to_setup[0].job.clientdir)
    192         os.system('tools/make_clean')
    193         os.chdir(cwd)
    194     elif not failed_tests:
    195         logging.error('### No test setup candidates ###')
    196         raise error.AutoservError('No test setup candidates.')
    197 
    198     for client_test in need_to_setup:
    199         good_setup = setup_test(client_test)
    200         if not good_setup:
    201             failed_tests.append(client_test.__class__.__name__)
    202 
    203     logging.info('############################# SUMMARY '
    204                  '#############################')
    205 
    206     # Print out tests that failed
    207     if failed_tests:
    208         logging.info('Finished setup -- The following tests failed')
    209         for failed_test in failed_tests:
    210             logging.info(failed_test)
    211     else:
    212         logging.info('Finished setup -- All tests built successfully')
    213     logging.info('######################### END SUMMARY '
    214                  '##############################')
    215     if failed_tests:
    216         raise error.AutoservError('Finished setup with errors.')
    217