unittest_suite.py revision cd7a81a58c7a1a16105dcd9dca5e9f1680eff65b
1#!/usr/bin/python -u 2 3import os, sys, unittest, optparse 4import common 5from autotest_lib.utils import parallel 6from autotest_lib.client.common_lib.test_utils import unittest as custom_unittest 7 8parser = optparse.OptionParser() 9parser.add_option("-r", action="store", type="string", dest="start", 10 default='', 11 help="root directory to start running unittests") 12parser.add_option("--full", action="store_true", dest="full", default=False, 13 help="whether to run the shortened version of the test") 14parser.add_option("--debug", action="store_true", dest="debug", default=False, 15 help="run in debug mode") 16parser.add_option("--skip-tests", dest="skip_tests", default=[], 17 help="A space separated list of tests to skip") 18 19 20REQUIRES_DJANGO = set(( 21 'monitor_db_unittest.py', 22 'monitor_db_functional_test.py', 23 'monitor_db_cleanup_test.py', 24 'frontend_unittest.py', 25 'csv_encoder_unittest.py', 26 'rpc_interface_unittest.py', 27 'models_test.py', 28 'scheduler_models_unittest.py', 29 'metahost_scheduler_unittest.py', 30 'site_metahost_scheduler_unittest.py', 31 'rpc_utils_unittest.py', 32 'site_rpc_utils_unittest.py', 33 'execution_engine_unittest.py', 34 'service_proxy_lib_test.py', 35 )) 36 37REQUIRES_MYSQLDB = set(( 38 'migrate_unittest.py', 39 'db_utils_unittest.py', 40 )) 41 42REQUIRES_GWT = set(( 43 'client_compilation_unittest.py', 44 )) 45 46REQUIRES_SIMPLEJSON = set(( 47 'resources_test.py', 48 'serviceHandler_unittest.py', 49 )) 50 51REQUIRES_AUTH = set (( 52 'trigger_unittest.py', 53 )) 54 55REQUIRES_HTTPLIB2 = set(( 56 )) 57 58LONG_RUNTIME = set(( 59 'barrier_unittest.py', 60 'logging_manager_test.py', 61 )) 62 63LONG_TESTS = (REQUIRES_DJANGO | 64 REQUIRES_MYSQLDB | 65 REQUIRES_GWT | 66 REQUIRES_SIMPLEJSON | 67 REQUIRES_HTTPLIB2 | 68 REQUIRES_AUTH | 69 LONG_RUNTIME) 70 71 72ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) 73 74 75class TestFailure(Exception): pass 76 77 78def run_test(mod_names, options): 79 """ 80 @param mod_names: A list of individual parts of the module name to import 81 and run as a test suite. 82 @param options: optparse options. 83 """ 84 if not options.debug: 85 parallel.redirect_io() 86 87 print "Running %s" % '.'.join(mod_names) 88 mod = common.setup_modules.import_module(mod_names[-1], 89 '.'.join(mod_names[:-1])) 90 for ut_module in [unittest, custom_unittest]: 91 test = ut_module.defaultTestLoader.loadTestsFromModule(mod) 92 suite = ut_module.TestSuite(test) 93 runner = ut_module.TextTestRunner(verbosity=2) 94 result = runner.run(suite) 95 if result.errors or result.failures: 96 msg = '%s had %d failures and %d errors.' 97 msg %= '.'.join(mod_names), len(result.failures), len(result.errors) 98 raise TestFailure(msg) 99 100 101def find_and_run_tests(start, options): 102 """ 103 Find and run Python unittest suites below the given directory. Only look 104 in subdirectories of start that are actual importable Python modules. 105 106 @param start: The absolute directory to look for tests under. 107 @param options: optparse options. 108 """ 109 modules = [] 110 skip_tests = set() 111 if options.skip_tests: 112 skip_tests.update(options.skip_tests.split()) 113 114 for dirpath, subdirs, filenames in os.walk(start): 115 # Only look in and below subdirectories that are python modules. 116 if '__init__.py' not in filenames: 117 if options.full: 118 for filename in filenames: 119 if filename.endswith('.pyc'): 120 os.unlink(os.path.join(dirpath, filename)) 121 # Skip all subdirectories below this one, it is not a module. 122 del subdirs[:] 123 if options.debug: 124 print 'Skipping', dirpath 125 continue # Skip this directory. 126 127 # Look for unittest files. 128 for fname in filenames: 129 if fname.endswith('_unittest.py') or fname.endswith('_test.py'): 130 if not options.full and fname in LONG_TESTS: 131 continue 132 if fname in skip_tests: 133 continue 134 path_no_py = os.path.join(dirpath, fname).rstrip('.py') 135 assert path_no_py.startswith(ROOT) 136 names = path_no_py[len(ROOT)+1:].split('/') 137 modules.append(['autotest_lib'] + names) 138 if options.debug: 139 print 'testing', path_no_py 140 141 if options.debug: 142 print 'Number of test modules found:', len(modules) 143 144 functions = {} 145 for module_names in modules: 146 # Create a function that'll test a particular module. module=module 147 # is a hack to force python to evaluate the params now. We then 148 # rename the function to make error reporting nicer. 149 run_module = lambda module=module_names: run_test(module, options) 150 name = '.'.join(module_names) 151 run_module.__name__ = name 152 functions[run_module] = set() 153 154 try: 155 dargs = {} 156 if options.debug: 157 dargs['max_simultaneous_procs'] = 1 158 pe = parallel.ParallelExecute(functions, **dargs) 159 pe.run_until_completion() 160 except parallel.ParallelError, err: 161 return err.errors 162 return [] 163 164 165def main(): 166 options, args = parser.parse_args() 167 if args: 168 parser.error('Unexpected argument(s): %s' % args) 169 parser.print_help() 170 sys.exit(1) 171 172 # Strip the arguments off the command line, so that the unit tests do not 173 # see them. 174 del sys.argv[1:] 175 176 absolute_start = os.path.join(ROOT, options.start) 177 errors = find_and_run_tests(absolute_start, options) 178 if errors: 179 print "%d tests resulted in an error/failure:" % len(errors) 180 for error in errors: 181 print "\t%s" % error 182 print "Rerun", sys.argv[0], "--debug to see the failure details." 183 sys.exit(1) 184 else: 185 print "All passed!" 186 sys.exit(0) 187 188 189if __name__ == "__main__": 190 main() 191