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