1# Copyright 2007 Google Inc. Released under the GPL v2 2# 3# Eric Li <ericli@google.com> 4 5import logging, os, pickle, re, sys 6import common 7 8from autotest_lib.client.bin import job as client_job 9from autotest_lib.client.common_lib import base_job 10from autotest_lib.client.common_lib import error 11from autotest_lib.client.common_lib import logging_manager 12from autotest_lib.client.common_lib import packages 13 14 15class 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 42def 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 93def 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 122def 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 160def 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