mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 1 | # Shell class for a test, inherited by all individual tests |
| 2 | # |
| 3 | # Methods: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 4 | # __init__ initialise |
| 5 | # initialize run once for each job |
| 6 | # setup run once for each new version of the test installed |
| 7 | # run run the test (wrapped by job.run_test()) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 8 | # |
| 9 | # Data: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 10 | # job backreference to the job this test instance is part of |
| 11 | # outputdir eg. results/<job>/<testname.tag> |
| 12 | # resultsdir eg. results/<job>/<testname.tag>/results |
| 13 | # profdir eg. results/<job>/<testname.tag>/profiling |
| 14 | # debugdir eg. results/<job>/<testname.tag>/debug |
| 15 | # bindir eg. tests/<test> |
| 16 | # src eg. tests/<test>/src |
jadmanski | 825e24c | 2008-08-27 20:54:31 +0000 | [diff] [blame] | 17 | # tmpdir eg. tmp/<tempname>_<testname.tag> |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 18 | |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 19 | import fcntl, os, re, sys, shutil, tarfile, tempfile, time, traceback |
mbligh | 6894ce2 | 2009-09-18 19:56:30 +0000 | [diff] [blame] | 20 | import warnings, logging, glob, resource |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 21 | |
jadmanski | c27c231 | 2009-08-05 20:58:51 +0000 | [diff] [blame] | 22 | from autotest_lib.client.common_lib import error |
mbligh | 53da18e | 2009-01-05 21:13:26 +0000 | [diff] [blame] | 23 | from autotest_lib.client.bin import utils |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 24 | |
| 25 | |
| 26 | class base_test: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 27 | preserve_srcdir = False |
jadmanski | 91d56a9 | 2009-04-01 15:20:40 +0000 | [diff] [blame] | 28 | network_destabilizing = False |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 29 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 30 | def __init__(self, job, bindir, outputdir): |
| 31 | self.job = job |
mbligh | 21e3358 | 2009-02-04 18:18:31 +0000 | [diff] [blame] | 32 | self.pkgmgr = job.pkgmgr |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 33 | self.autodir = job.autodir |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 34 | self.outputdir = outputdir |
showard | b18134f | 2009-03-20 20:52:18 +0000 | [diff] [blame] | 35 | self.tagged_testname = os.path.basename(self.outputdir) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 36 | self.resultsdir = os.path.join(self.outputdir, 'results') |
| 37 | os.mkdir(self.resultsdir) |
| 38 | self.profdir = os.path.join(self.outputdir, 'profiling') |
| 39 | os.mkdir(self.profdir) |
| 40 | self.debugdir = os.path.join(self.outputdir, 'debug') |
| 41 | os.mkdir(self.debugdir) |
mbligh | 6894ce2 | 2009-09-18 19:56:30 +0000 | [diff] [blame] | 42 | self.configure_crash_handler() |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 43 | self.bindir = bindir |
| 44 | if hasattr(job, 'libdir'): |
| 45 | self.libdir = job.libdir |
| 46 | self.srcdir = os.path.join(self.bindir, 'src') |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 47 | self.tmpdir = tempfile.mkdtemp("_" + self.tagged_testname, |
showard | b18134f | 2009-03-20 20:52:18 +0000 | [diff] [blame] | 48 | dir=job.tmpdir) |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 49 | self._keyvals = [] |
| 50 | self._new_keyval = False |
mbligh | 32cb5b4 | 2009-05-01 23:05:09 +0000 | [diff] [blame] | 51 | self.failed_constraints = [] |
mbligh | 5e703a2 | 2009-06-15 22:00:12 +0000 | [diff] [blame] | 52 | self.iteration = 0 |
mbligh | 742ae42 | 2009-05-13 20:46:41 +0000 | [diff] [blame] | 53 | self.before_iteration_hooks = [] |
| 54 | self.after_iteration_hooks = [] |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 55 | |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 56 | |
mbligh | 6894ce2 | 2009-09-18 19:56:30 +0000 | [diff] [blame] | 57 | def configure_crash_handler(self): |
| 58 | """ |
| 59 | Configure the crash handler by: |
| 60 | * Setting up core size to unlimited |
| 61 | * Putting an appropriate crash handler on /proc/sys/kernel/core_pattern |
| 62 | * Create files that the crash handler will use to figure which tests |
| 63 | are active at a given moment |
| 64 | |
| 65 | The crash handler will pick up the core file and write it to |
| 66 | self.debugdir, and perform analysis on it to generate a report. The |
| 67 | program also outputs some results to syslog. |
| 68 | |
| 69 | If multiple tests are running, an attempt to verify if we still have |
| 70 | the old PID on the system process table to determine whether it is a |
| 71 | parent of the current test execution. If we can't determine it, the |
| 72 | core file and the report file will be copied to all test debug dirs. |
| 73 | """ |
| 74 | self.pattern_file = '/proc/sys/kernel/core_pattern' |
| 75 | try: |
| 76 | # Enable core dumps |
| 77 | resource.setrlimit(resource.RLIMIT_CORE, (-1, -1)) |
| 78 | # Trying to backup core pattern and register our script |
| 79 | self.core_pattern_backup = open(self.pattern_file, 'r').read() |
| 80 | pattern_file = open(self.pattern_file, 'w') |
| 81 | tools_dir = os.path.join(self.autodir, 'tools') |
| 82 | crash_handler_path = os.path.join(tools_dir, 'crash_handler.py') |
| 83 | pattern_file.write('|' + crash_handler_path + ' %p %t %u %s %h %e') |
| 84 | # Writing the files that the crash handler is going to use |
| 85 | self.debugdir_tmp_file = ('/tmp/autotest_results_dir.%s' % |
| 86 | os.getpid()) |
| 87 | utils.open_write_close(self.debugdir_tmp_file, self.debugdir + "\n") |
| 88 | except Exception, e: |
| 89 | self.crash_handling_enabled = False |
| 90 | logging.error('Crash handling system disabled: %s' % e) |
| 91 | else: |
| 92 | self.crash_handling_enabled = True |
| 93 | logging.debug('Crash handling system enabled.') |
| 94 | |
| 95 | |
| 96 | def crash_handler_report(self): |
| 97 | """ |
| 98 | If core dumps are found on the debugdir after the execution of the |
| 99 | test, let the user know. |
| 100 | """ |
| 101 | if self.crash_handling_enabled: |
| 102 | core_dirs = glob.glob('%s/crash.*' % self.debugdir) |
| 103 | if core_dirs: |
| 104 | logging.warning('Programs crashed during test execution:') |
| 105 | for dir in core_dirs: |
| 106 | logging.warning('Please verify %s for more info', dir) |
| 107 | # Remove the debugdir info file |
| 108 | os.unlink(self.debugdir_tmp_file) |
| 109 | # Restore the core pattern backup |
| 110 | try: |
| 111 | utils.open_write_close(self.pattern_file, |
| 112 | self.core_pattern_backup) |
| 113 | except EnvironmentError: |
| 114 | pass |
| 115 | |
| 116 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 117 | def assert_(self, expr, msg='Assertion failed.'): |
| 118 | if not expr: |
| 119 | raise error.TestError(msg) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 120 | |
| 121 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 122 | def write_test_keyval(self, attr_dict): |
| 123 | utils.write_keyval(self.outputdir, attr_dict) |
jadmanski | cc54917 | 2008-05-21 18:11:51 +0000 | [diff] [blame] | 124 | |
| 125 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 126 | @staticmethod |
| 127 | def _append_type_to_keys(dictionary, typename): |
| 128 | new_dict = {} |
| 129 | for key, value in dictionary.iteritems(): |
| 130 | new_key = "%s{%s}" % (key, typename) |
| 131 | new_dict[new_key] = value |
| 132 | return new_dict |
jadmanski | cc54917 | 2008-05-21 18:11:51 +0000 | [diff] [blame] | 133 | |
| 134 | |
mbligh | 0b3dd5f | 2008-07-16 20:37:13 +0000 | [diff] [blame] | 135 | def write_perf_keyval(self, perf_dict): |
| 136 | self.write_iteration_keyval({}, perf_dict) |
jadmanski | cc54917 | 2008-05-21 18:11:51 +0000 | [diff] [blame] | 137 | |
mbligh | 0b3dd5f | 2008-07-16 20:37:13 +0000 | [diff] [blame] | 138 | |
| 139 | def write_attr_keyval(self, attr_dict): |
| 140 | self.write_iteration_keyval(attr_dict, {}) |
| 141 | |
| 142 | |
| 143 | def write_iteration_keyval(self, attr_dict, perf_dict): |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 144 | # append the dictionaries before they have the {perf} and {attr} added |
| 145 | self._keyvals.append({'attr':attr_dict, 'perf':perf_dict}) |
| 146 | self._new_keyval = True |
| 147 | |
mbligh | 0b3dd5f | 2008-07-16 20:37:13 +0000 | [diff] [blame] | 148 | if attr_dict: |
| 149 | attr_dict = self._append_type_to_keys(attr_dict, "attr") |
| 150 | utils.write_keyval(self.resultsdir, attr_dict, type_tag="attr") |
| 151 | |
| 152 | if perf_dict: |
| 153 | perf_dict = self._append_type_to_keys(perf_dict, "perf") |
| 154 | utils.write_keyval(self.resultsdir, perf_dict, type_tag="perf") |
jadmanski | cc54917 | 2008-05-21 18:11:51 +0000 | [diff] [blame] | 155 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 156 | keyval_path = os.path.join(self.resultsdir, "keyval") |
| 157 | print >> open(keyval_path, "a"), "" |
jadmanski | cc54917 | 2008-05-21 18:11:51 +0000 | [diff] [blame] | 158 | |
| 159 | |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 160 | def analyze_perf_constraints(self, constraints): |
| 161 | if not self._new_keyval: |
| 162 | return |
| 163 | |
| 164 | self._new_keyval = False |
mbligh | 32cb5b4 | 2009-05-01 23:05:09 +0000 | [diff] [blame] | 165 | failures = [] |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 166 | for constraint in constraints: |
| 167 | print "___________________ constraint = %s" % constraint |
| 168 | print "___________________ keyvals = %s" % self._keyvals[-1]['perf'] |
| 169 | try: |
| 170 | if not eval(constraint, self._keyvals[-1]['perf']): |
mbligh | 8beabca | 2009-05-21 01:33:15 +0000 | [diff] [blame] | 171 | failures.append('%s: constraint was not met' % constraint) |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 172 | except: |
mbligh | 32cb5b4 | 2009-05-01 23:05:09 +0000 | [diff] [blame] | 173 | failures.append('could not evaluate constraint: %s' |
| 174 | % constraint) |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 175 | |
mbligh | 32cb5b4 | 2009-05-01 23:05:09 +0000 | [diff] [blame] | 176 | # keep track of the errors for each iteration |
| 177 | self.failed_constraints.append(failures) |
| 178 | |
| 179 | |
| 180 | def process_failed_constraints(self): |
| 181 | msg = '' |
| 182 | for i, failures in enumerate(self.failed_constraints): |
| 183 | if failures: |
| 184 | msg += 'iteration %d:%s ' % (i, ','.join(failures)) |
| 185 | |
| 186 | if msg: |
| 187 | raise error.TestFail(msg) |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 188 | |
| 189 | |
mbligh | 742ae42 | 2009-05-13 20:46:41 +0000 | [diff] [blame] | 190 | def register_before_iteration_hook(self, iteration_hook): |
| 191 | """ |
| 192 | This is how we expect test writers to register a before_iteration_hook. |
| 193 | This adds the method to the list of hooks which are executed |
| 194 | before each iteration. |
| 195 | |
| 196 | @param iteration_hook: Method to run before each iteration. A valid |
| 197 | hook accepts a single argument which is the |
| 198 | test object. |
| 199 | """ |
| 200 | self.before_iteration_hooks.append(iteration_hook) |
| 201 | |
| 202 | |
| 203 | def register_after_iteration_hook(self, iteration_hook): |
| 204 | """ |
| 205 | This is how we expect test writers to register an after_iteration_hook. |
| 206 | This adds the method to the list of hooks which are executed |
| 207 | after each iteration. |
| 208 | |
| 209 | @param iteration_hook: Method to run after each iteration. A valid |
| 210 | hook accepts a single argument which is the |
| 211 | test object. |
| 212 | """ |
| 213 | self.after_iteration_hooks.append(iteration_hook) |
| 214 | |
| 215 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 216 | def initialize(self): |
| 217 | pass |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 218 | |
| 219 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 220 | def setup(self): |
| 221 | pass |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 222 | |
| 223 | |
mbligh | 14f9856 | 2008-07-29 21:16:27 +0000 | [diff] [blame] | 224 | def warmup(self, *args, **dargs): |
mbligh | 4205d89 | 2008-07-14 16:23:20 +0000 | [diff] [blame] | 225 | pass |
mbligh | b53a347 | 2008-07-11 21:27:58 +0000 | [diff] [blame] | 226 | |
| 227 | |
mbligh | b5dac43 | 2008-11-27 00:38:44 +0000 | [diff] [blame] | 228 | def drop_caches_between_iterations(self): |
| 229 | if self.job.drop_caches_between_iterations: |
| 230 | print "Dropping caches between iterations" |
mbligh | 53da18e | 2009-01-05 21:13:26 +0000 | [diff] [blame] | 231 | utils.drop_caches() |
mbligh | b5dac43 | 2008-11-27 00:38:44 +0000 | [diff] [blame] | 232 | |
| 233 | |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 234 | def _call_run_once(self, constraints, profile_only, |
| 235 | postprocess_profiled_run, args, dargs): |
mbligh | 6b97f79 | 2009-03-23 21:23:12 +0000 | [diff] [blame] | 236 | self.drop_caches_between_iterations() |
mbligh | 4395bbd | 2009-03-25 19:34:17 +0000 | [diff] [blame] | 237 | |
| 238 | # execute iteration hooks |
mbligh | 742ae42 | 2009-05-13 20:46:41 +0000 | [diff] [blame] | 239 | for hook in self.before_iteration_hooks: |
| 240 | hook(self) |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 241 | |
| 242 | if profile_only: |
| 243 | self.run_once_profiling(postprocess_profiled_run, *args, **dargs) |
| 244 | else: |
| 245 | self.run_once(*args, **dargs) |
| 246 | |
mbligh | 742ae42 | 2009-05-13 20:46:41 +0000 | [diff] [blame] | 247 | for hook in self.after_iteration_hooks: |
| 248 | hook(self) |
mbligh | 4395bbd | 2009-03-25 19:34:17 +0000 | [diff] [blame] | 249 | |
mbligh | 6b97f79 | 2009-03-23 21:23:12 +0000 | [diff] [blame] | 250 | self.postprocess_iteration() |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 251 | self.analyze_perf_constraints(constraints) |
mbligh | 6b97f79 | 2009-03-23 21:23:12 +0000 | [diff] [blame] | 252 | |
| 253 | |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 254 | def execute(self, iterations=None, test_length=None, profile_only=False, |
mbligh | a49c5cb | 2009-02-26 01:01:09 +0000 | [diff] [blame] | 255 | _get_time=time.time, postprocess_profiled_run=None, |
mbligh | 7af0997 | 2009-04-17 22:17:08 +0000 | [diff] [blame] | 256 | constraints=(), *args, **dargs): |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 257 | """ |
| 258 | This is the basic execute method for the tests inherited from base_test. |
| 259 | If you want to implement a benchmark test, it's better to implement |
| 260 | the run_once function, to cope with the profiling infrastructure. For |
| 261 | other tests, you can just override the default implementation. |
mbligh | 6043471 | 2008-07-16 16:35:10 +0000 | [diff] [blame] | 262 | |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 263 | @param test_length: The minimum test length in seconds. We'll run the |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 264 | run_once function for a number of times large enough to cover the |
| 265 | minimum test length. |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 266 | |
| 267 | @param iterations: A number of iterations that we'll run the run_once |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 268 | function. This parameter is incompatible with test_length and will |
| 269 | be silently ignored if you specify both. |
| 270 | |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 271 | @param profile_only: If true run X iterations with profilers enabled. |
| 272 | Otherwise run X iterations and one with profiling if profiles are |
| 273 | enabled. |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 274 | |
| 275 | @param _get_time: [time.time] Used for unit test time injection. |
mbligh | c931408 | 2009-02-26 00:48:18 +0000 | [diff] [blame] | 276 | |
mbligh | a49c5cb | 2009-02-26 01:01:09 +0000 | [diff] [blame] | 277 | @param postprocess_profiled_run: Run the postprocessing for the |
| 278 | profiled run. |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 279 | """ |
| 280 | |
| 281 | # For our special class of tests, the benchmarks, we don't want |
| 282 | # profilers to run during the test iterations. Let's reserve only |
| 283 | # the last iteration for profiling, if needed. So let's stop |
| 284 | # all profilers if they are present and active. |
mbligh | b3c0c91 | 2008-11-27 00:32:45 +0000 | [diff] [blame] | 285 | profilers = self.job.profilers |
| 286 | if profilers.active(): |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 287 | profilers.stop(self) |
| 288 | # If the user called this test in an odd way (specified both iterations |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 289 | # and test_length), let's warn them. |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 290 | if iterations and test_length: |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 291 | logging.info('Iterations parameter ignored (timed execution).') |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 292 | if test_length: |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 293 | test_start = _get_time() |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 294 | time_elapsed = 0 |
| 295 | timed_counter = 0 |
showard | b18134f | 2009-03-20 20:52:18 +0000 | [diff] [blame] | 296 | logging.info('Test started. Minimum test length: %d s', |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 297 | test_length) |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 298 | while time_elapsed < test_length: |
| 299 | timed_counter = timed_counter + 1 |
| 300 | if time_elapsed == 0: |
showard | b18134f | 2009-03-20 20:52:18 +0000 | [diff] [blame] | 301 | logging.info('Executing iteration %d', timed_counter) |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 302 | elif time_elapsed > 0: |
showard | b18134f | 2009-03-20 20:52:18 +0000 | [diff] [blame] | 303 | logging.info( |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 304 | 'Executing iteration %d, time_elapsed %d s', |
| 305 | timed_counter, time_elapsed) |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 306 | self._call_run_once(constraints, profile_only, |
| 307 | postprocess_profiled_run, args, dargs) |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 308 | test_iteration_finish = _get_time() |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 309 | time_elapsed = test_iteration_finish - test_start |
showard | b18134f | 2009-03-20 20:52:18 +0000 | [diff] [blame] | 310 | logging.info('Test finished after %d iterations', |
mbligh | 4b835b8 | 2009-02-11 01:26:13 +0000 | [diff] [blame] | 311 | timed_counter) |
showard | b18134f | 2009-03-20 20:52:18 +0000 | [diff] [blame] | 312 | logging.info('Time elapsed: %d s', time_elapsed) |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 313 | else: |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 314 | if iterations is None: |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 315 | iterations = 1 |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 316 | logging.info('Test started. Number of iterations: %d', iterations) |
| 317 | for self.iteration in xrange(1, iterations+1): |
| 318 | logging.info('Executing iteration %d of %d', self.iteration, |
| 319 | iterations) |
| 320 | self._call_run_once(constraints, profile_only, |
| 321 | postprocess_profiled_run, args, dargs) |
| 322 | logging.info('Test finished after %d iterations.', iterations) |
mbligh | 6043471 | 2008-07-16 16:35:10 +0000 | [diff] [blame] | 323 | |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 324 | if not profile_only: |
mbligh | 5e703a2 | 2009-06-15 22:00:12 +0000 | [diff] [blame] | 325 | self.iteration += 1 |
mbligh | f58865f | 2009-05-13 21:32:42 +0000 | [diff] [blame] | 326 | self.run_once_profiling(postprocess_profiled_run, *args, **dargs) |
mbligh | d27604e | 2009-02-03 02:06:08 +0000 | [diff] [blame] | 327 | |
| 328 | # Do any postprocessing, normally extracting performance keyvals, etc |
| 329 | self.postprocess() |
mbligh | 32cb5b4 | 2009-05-01 23:05:09 +0000 | [diff] [blame] | 330 | self.process_failed_constraints() |
mbligh | d27604e | 2009-02-03 02:06:08 +0000 | [diff] [blame] | 331 | |
| 332 | |
mbligh | a49c5cb | 2009-02-26 01:01:09 +0000 | [diff] [blame] | 333 | def run_once_profiling(self, postprocess_profiled_run, *args, **dargs): |
mbligh | d27604e | 2009-02-03 02:06:08 +0000 | [diff] [blame] | 334 | profilers = self.job.profilers |
mbligh | 6043471 | 2008-07-16 16:35:10 +0000 | [diff] [blame] | 335 | # Do a profiling run if necessary |
mbligh | b3c0c91 | 2008-11-27 00:32:45 +0000 | [diff] [blame] | 336 | if profilers.present(): |
mbligh | c931408 | 2009-02-26 00:48:18 +0000 | [diff] [blame] | 337 | self.drop_caches_between_iterations() |
mbligh | 6043471 | 2008-07-16 16:35:10 +0000 | [diff] [blame] | 338 | profilers.start(self) |
mbligh | 777d96e | 2008-09-03 16:34:38 +0000 | [diff] [blame] | 339 | print 'Profilers present. Profiling run started' |
jadmanski | 0d39007 | 2008-11-19 21:19:56 +0000 | [diff] [blame] | 340 | try: |
| 341 | self.run_once(*args, **dargs) |
mbligh | a49c5cb | 2009-02-26 01:01:09 +0000 | [diff] [blame] | 342 | |
| 343 | # Priority to the run_once() argument over the attribute. |
| 344 | postprocess_attribute = getattr(self, |
| 345 | 'postprocess_profiled_run', |
| 346 | False) |
| 347 | |
| 348 | if (postprocess_profiled_run or |
| 349 | (postprocess_profiled_run is None and |
| 350 | postprocess_attribute)): |
| 351 | self.postprocess_iteration() |
| 352 | |
jadmanski | 0d39007 | 2008-11-19 21:19:56 +0000 | [diff] [blame] | 353 | finally: |
| 354 | profilers.stop(self) |
| 355 | profilers.report(self) |
mbligh | 6043471 | 2008-07-16 16:35:10 +0000 | [diff] [blame] | 356 | |
mbligh | 6043471 | 2008-07-16 16:35:10 +0000 | [diff] [blame] | 357 | |
| 358 | def postprocess(self): |
| 359 | pass |
| 360 | |
| 361 | |
mbligh | 34b297b | 2009-02-03 17:49:48 +0000 | [diff] [blame] | 362 | def postprocess_iteration(self): |
| 363 | pass |
| 364 | |
| 365 | |
mbligh | 6043471 | 2008-07-16 16:35:10 +0000 | [diff] [blame] | 366 | def cleanup(self): |
| 367 | pass |
mbligh | cd8a516 | 2008-07-16 16:32:12 +0000 | [diff] [blame] | 368 | |
| 369 | |
mbligh | 742ae42 | 2009-05-13 20:46:41 +0000 | [diff] [blame] | 370 | def _exec(self, args, dargs): |
showard | ee36bc7 | 2009-06-18 23:13:53 +0000 | [diff] [blame] | 371 | self.job.logging.tee_redirect_debug_dir(self.debugdir, |
| 372 | log_name=self.tagged_testname) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 373 | try: |
jadmanski | 91d56a9 | 2009-04-01 15:20:40 +0000 | [diff] [blame] | 374 | if self.network_destabilizing: |
| 375 | self.job.disable_warnings("NETWORK") |
| 376 | |
jadmanski | 6265578 | 2008-07-28 21:27:46 +0000 | [diff] [blame] | 377 | # write out the test attributes into a keyval |
| 378 | dargs = dargs.copy() |
jadmanski | 23afbec | 2008-09-17 18:12:07 +0000 | [diff] [blame] | 379 | run_cleanup = dargs.pop('run_cleanup', self.job.run_test_cleanup) |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 380 | keyvals = dargs.pop('test_attributes', {}).copy() |
jadmanski | 6265578 | 2008-07-28 21:27:46 +0000 | [diff] [blame] | 381 | keyvals['version'] = self.version |
jadmanski | 2ae0e05 | 2008-09-04 16:37:28 +0000 | [diff] [blame] | 382 | for i, arg in enumerate(args): |
| 383 | keyvals['param-%d' % i] = repr(arg) |
| 384 | for name, arg in dargs.iteritems(): |
| 385 | keyvals['param-%s' % name] = repr(arg) |
jadmanski | 6265578 | 2008-07-28 21:27:46 +0000 | [diff] [blame] | 386 | self.write_test_keyval(keyvals) |
| 387 | |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 388 | _validate_args(args, dargs, self.initialize, self.setup, |
| 389 | self.execute, self.cleanup) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 390 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 391 | try: |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 392 | # Initialize: |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 393 | _cherry_pick_call(self.initialize, *args, **dargs) |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 394 | |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 395 | lockfile = open(os.path.join(self.job.tmpdir, '.testlock'), 'w') |
| 396 | try: |
| 397 | fcntl.flock(lockfile, fcntl.LOCK_EX) |
| 398 | # Setup: (compile and install the test, if needed) |
| 399 | p_args, p_dargs = _cherry_pick_args(self.setup,args,dargs) |
| 400 | utils.update_version(self.srcdir, self.preserve_srcdir, |
| 401 | self.version, self.setup, |
| 402 | *p_args, **p_dargs) |
| 403 | finally: |
| 404 | fcntl.flock(lockfile, fcntl.LOCK_UN) |
| 405 | lockfile.close() |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 406 | |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 407 | # Execute: |
jadmanski | 6265578 | 2008-07-28 21:27:46 +0000 | [diff] [blame] | 408 | os.chdir(self.outputdir) |
mbligh | 4395bbd | 2009-03-25 19:34:17 +0000 | [diff] [blame] | 409 | |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 410 | # call self.warmup cherry picking the arguments it accepts and |
| 411 | # translate exceptions if needed |
| 412 | _call_test_function(_cherry_pick_call, self.warmup, |
| 413 | *args, **dargs) |
| 414 | |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 415 | if hasattr(self, 'run_once'): |
| 416 | p_args, p_dargs = _cherry_pick_args(self.run_once, |
| 417 | args, dargs) |
jadmanski | 886c81f | 2009-02-19 12:54:03 +0000 | [diff] [blame] | 418 | # pull in any non-* and non-** args from self.execute |
| 419 | for param in _get_nonstar_args(self.execute): |
| 420 | if param in dargs: |
| 421 | p_dargs[param] = dargs[param] |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 422 | else: |
| 423 | p_args, p_dargs = _cherry_pick_args(self.execute, |
| 424 | args, dargs) |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 425 | |
| 426 | _call_test_function(self.execute, *p_args, **p_dargs) |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 427 | except Exception: |
| 428 | # Save the exception while we run our cleanup() before |
| 429 | # reraising it. |
jadmanski | d625c7f | 2008-08-27 14:08:52 +0000 | [diff] [blame] | 430 | exc_info = sys.exc_info() |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 431 | try: |
| 432 | try: |
| 433 | if run_cleanup: |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 434 | _cherry_pick_call(self.cleanup, *args, **dargs) |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 435 | except Exception: |
| 436 | print 'Ignoring exception during cleanup() phase:' |
| 437 | traceback.print_exc() |
| 438 | print 'Now raising the earlier %s error' % exc_info[0] |
mbligh | 6894ce2 | 2009-09-18 19:56:30 +0000 | [diff] [blame] | 439 | self.crash_handler_report() |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 440 | finally: |
showard | 75cdfee | 2009-06-10 17:40:41 +0000 | [diff] [blame] | 441 | self.job.logging.restore() |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 442 | try: |
| 443 | raise exc_info[0], exc_info[1], exc_info[2] |
| 444 | finally: |
| 445 | # http://docs.python.org/library/sys.html#sys.exc_info |
| 446 | # Be nice and prevent a circular reference. |
| 447 | del exc_info |
jadmanski | d625c7f | 2008-08-27 14:08:52 +0000 | [diff] [blame] | 448 | else: |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 449 | try: |
| 450 | if run_cleanup: |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 451 | _cherry_pick_call(self.cleanup, *args, **dargs) |
mbligh | 6894ce2 | 2009-09-18 19:56:30 +0000 | [diff] [blame] | 452 | self.crash_handler_report() |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 453 | finally: |
showard | 75cdfee | 2009-06-10 17:40:41 +0000 | [diff] [blame] | 454 | self.job.logging.restore() |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 455 | except error.AutotestError: |
jadmanski | 91d56a9 | 2009-04-01 15:20:40 +0000 | [diff] [blame] | 456 | if self.network_destabilizing: |
| 457 | self.job.enable_warnings("NETWORK") |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 458 | # Pass already-categorized errors on up. |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 459 | raise |
| 460 | except Exception, e: |
jadmanski | 91d56a9 | 2009-04-01 15:20:40 +0000 | [diff] [blame] | 461 | if self.network_destabilizing: |
| 462 | self.job.enable_warnings("NETWORK") |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 463 | # Anything else is an ERROR in our own code, not execute(). |
mbligh | c218083 | 2008-07-25 03:26:12 +0000 | [diff] [blame] | 464 | raise error.UnhandledTestError(e) |
jadmanski | 91d56a9 | 2009-04-01 15:20:40 +0000 | [diff] [blame] | 465 | else: |
| 466 | if self.network_destabilizing: |
| 467 | self.job.enable_warnings("NETWORK") |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 468 | |
| 469 | |
jadmanski | 886c81f | 2009-02-19 12:54:03 +0000 | [diff] [blame] | 470 | def _get_nonstar_args(func): |
| 471 | """Extract all the (normal) function parameter names. |
| 472 | |
| 473 | Given a function, returns a tuple of parameter names, specifically |
| 474 | excluding the * and ** parameters, if the function accepts them. |
| 475 | |
| 476 | @param func: A callable that we want to chose arguments for. |
| 477 | |
| 478 | @return: A tuple of parameters accepted by the function. |
| 479 | """ |
| 480 | return func.func_code.co_varnames[:func.func_code.co_argcount] |
| 481 | |
| 482 | |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 483 | def _cherry_pick_args(func, args, dargs): |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 484 | """Sanitize positional and keyword arguments before calling a function. |
| 485 | |
| 486 | Given a callable (func), an argument tuple and a dictionary of keyword |
| 487 | arguments, pick only those arguments which the function is prepared to |
| 488 | accept and return a new argument tuple and keyword argument dictionary. |
| 489 | |
| 490 | Args: |
| 491 | func: A callable that we want to choose arguments for. |
| 492 | args: A tuple of positional arguments to consider passing to func. |
| 493 | dargs: A dictionary of keyword arguments to consider passing to func. |
| 494 | Returns: |
| 495 | A tuple of: (args tuple, keyword arguments dictionary) |
| 496 | """ |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 497 | # Cherry pick args: |
| 498 | if func.func_code.co_flags & 0x04: |
| 499 | # func accepts *args, so return the entire args. |
| 500 | p_args = args |
| 501 | else: |
| 502 | p_args = () |
| 503 | |
| 504 | # Cherry pick dargs: |
| 505 | if func.func_code.co_flags & 0x08: |
| 506 | # func accepts **dargs, so return the entire dargs. |
| 507 | p_dargs = dargs |
| 508 | else: |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 509 | # Only return the keyword arguments that func accepts. |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 510 | p_dargs = {} |
jadmanski | 886c81f | 2009-02-19 12:54:03 +0000 | [diff] [blame] | 511 | for param in _get_nonstar_args(func): |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 512 | if param in dargs: |
| 513 | p_dargs[param] = dargs[param] |
| 514 | |
| 515 | return p_args, p_dargs |
| 516 | |
| 517 | |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 518 | def _cherry_pick_call(func, *args, **dargs): |
| 519 | """Cherry picks arguments from args/dargs based on what "func" accepts |
| 520 | and calls the function with the picked arguments.""" |
| 521 | p_args, p_dargs = _cherry_pick_args(func, args, dargs) |
| 522 | return func(*p_args, **p_dargs) |
| 523 | |
| 524 | |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 525 | def _validate_args(args, dargs, *funcs): |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 526 | """Verify that arguments are appropriate for at least one callable. |
| 527 | |
| 528 | Given a list of callables as additional parameters, verify that |
| 529 | the proposed keyword arguments in dargs will each be accepted by at least |
| 530 | one of the callables. |
| 531 | |
| 532 | NOTE: args is currently not supported and must be empty. |
| 533 | |
| 534 | Args: |
| 535 | args: A tuple of proposed positional arguments. |
| 536 | dargs: A dictionary of proposed keyword arguments. |
| 537 | *funcs: Callables to be searched for acceptance of args and dargs. |
| 538 | Raises: |
| 539 | error.AutotestError: if an arg won't be accepted by any of *funcs. |
| 540 | """ |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 541 | all_co_flags = 0 |
| 542 | all_varnames = () |
| 543 | for func in funcs: |
| 544 | all_co_flags |= func.func_code.co_flags |
| 545 | all_varnames += func.func_code.co_varnames[:func.func_code.co_argcount] |
| 546 | |
| 547 | # Check if given args belongs to at least one of the methods below. |
| 548 | if len(args) > 0: |
| 549 | # Current implementation doesn't allow the use of args. |
mbligh | 234a84f | 2008-11-20 19:57:43 +0000 | [diff] [blame] | 550 | raise error.TestError('Unnamed arguments not accepted. Please ' |
| 551 | 'call job.run_test with named args only') |
mbligh | cf23819 | 2008-07-17 01:18:44 +0000 | [diff] [blame] | 552 | |
| 553 | # Check if given dargs belongs to at least one of the methods below. |
| 554 | if len(dargs) > 0: |
| 555 | if not all_co_flags & 0x08: |
| 556 | # no func accepts *dargs, so: |
| 557 | for param in dargs: |
| 558 | if not param in all_varnames: |
| 559 | raise error.AutotestError('Unknown parameter: %s' % param) |
| 560 | |
| 561 | |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 562 | def _installtest(job, url): |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 563 | (group, name) = job.pkgmgr.get_package_name(url, 'test') |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 564 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 565 | # Bail if the test is already installed |
| 566 | group_dir = os.path.join(job.testdir, "download", group) |
| 567 | if os.path.exists(os.path.join(group_dir, name)): |
| 568 | return (group, name) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 569 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 570 | # If the group directory is missing create it and add |
| 571 | # an empty __init__.py so that sub-directories are |
| 572 | # considered for import. |
| 573 | if not os.path.exists(group_dir): |
| 574 | os.mkdir(group_dir) |
| 575 | f = file(os.path.join(group_dir, '__init__.py'), 'w+') |
| 576 | f.close() |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 577 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 578 | print name + ": installing test url=" + url |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 579 | tarball = os.path.basename(url) |
| 580 | tarball_path = os.path.join(group_dir, tarball) |
| 581 | test_dir = os.path.join(group_dir, name) |
| 582 | job.pkgmgr.fetch_pkg(tarball, tarball_path, |
| 583 | repo_url = os.path.dirname(url)) |
| 584 | |
| 585 | # Create the directory for the test |
| 586 | if not os.path.exists(test_dir): |
| 587 | os.mkdir(os.path.join(group_dir, name)) |
| 588 | |
| 589 | job.pkgmgr.untar_pkg(tarball_path, test_dir) |
| 590 | |
| 591 | os.remove(tarball_path) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 592 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 593 | # For this 'sub-object' to be importable via the name |
| 594 | # 'group.name' we need to provide an __init__.py, |
| 595 | # so link the main entry point to this. |
| 596 | os.symlink(name + '.py', os.path.join(group_dir, name, |
| 597 | '__init__.py')) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 598 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 599 | # The test is now installed. |
| 600 | return (group, name) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 601 | |
| 602 | |
mbligh | 5c1bb25 | 2009-03-25 22:06:49 +0000 | [diff] [blame] | 603 | def _call_test_function(func, *args, **dargs): |
| 604 | """Calls a test function and translates exceptions so that errors |
| 605 | inside test code are considered test failures.""" |
| 606 | try: |
| 607 | return func(*args, **dargs) |
| 608 | except error.AutotestError: |
| 609 | # Pass already-categorized errors on up as is. |
| 610 | raise |
| 611 | except Exception, e: |
| 612 | # Other exceptions must be treated as a FAIL when |
| 613 | # raised during the test functions |
| 614 | raise error.UnhandledTestFail(e) |
| 615 | |
| 616 | |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 617 | def runtest(job, url, tag, args, dargs, |
jadmanski | 30e9b59 | 2008-09-25 19:51:57 +0000 | [diff] [blame] | 618 | local_namespace={}, global_namespace={}, |
mbligh | 4395bbd | 2009-03-25 19:34:17 +0000 | [diff] [blame] | 619 | before_test_hook=None, after_test_hook=None, |
| 620 | before_iteration_hook=None, after_iteration_hook=None): |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 621 | local_namespace = local_namespace.copy() |
| 622 | global_namespace = global_namespace.copy() |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 623 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 624 | # if this is not a plain test name then download and install the |
| 625 | # specified test |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 626 | if url.endswith('.tar.bz2'): |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 627 | (group, testname) = _installtest(job, url) |
| 628 | bindir = os.path.join(job.testdir, 'download', group, testname) |
| 629 | site_bindir = None |
| 630 | else: |
| 631 | # if the test is local, it can be found in either testdir |
| 632 | # or site_testdir. tests in site_testdir override tests |
| 633 | # defined in testdir |
| 634 | (group, testname) = ('', url) |
| 635 | bindir = os.path.join(job.testdir, group, testname) |
| 636 | if hasattr(job, 'site_testdir'): |
| 637 | site_bindir = os.path.join(job.site_testdir, |
| 638 | group, testname) |
| 639 | else: |
| 640 | site_bindir = None |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 641 | |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 642 | # The job object here can be that of a server side job or a client |
| 643 | # side job. 'install_pkg' method won't be present for server side |
| 644 | # jobs, so do the fetch only if that method is present in the job |
| 645 | # obj. |
| 646 | if hasattr(job, 'install_pkg'): |
| 647 | try: |
| 648 | job.install_pkg(testname, 'test', bindir) |
jadmanski | c27c231 | 2009-08-05 20:58:51 +0000 | [diff] [blame] | 649 | except error.PackageInstallError, e: |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 650 | # continue as a fall back mechanism and see if the test code |
| 651 | # already exists on the machine |
| 652 | pass |
| 653 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 654 | outputdir = os.path.join(job.resultdir, testname) |
| 655 | if tag: |
| 656 | outputdir += '.' + tag |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 657 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 658 | # if we can find the test in site_bindir, use this version |
| 659 | if site_bindir and os.path.exists(site_bindir): |
| 660 | bindir = site_bindir |
| 661 | testdir = job.site_testdir |
| 662 | elif os.path.exists(bindir): |
| 663 | testdir = job.testdir |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 664 | else: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 665 | raise error.TestError(testname + ': test does not exist') |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 666 | |
mbligh | c5ddfd1 | 2008-08-04 17:15:00 +0000 | [diff] [blame] | 667 | local_namespace['job'] = job |
| 668 | local_namespace['bindir'] = bindir |
| 669 | local_namespace['outputdir'] = outputdir |
| 670 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 671 | if group: |
| 672 | sys.path.insert(0, os.path.join(testdir, 'download')) |
| 673 | group += '.' |
| 674 | else: |
| 675 | sys.path.insert(0, os.path.join(testdir, testname)) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 676 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 677 | try: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 678 | exec ("import %s%s" % (group, testname), |
| 679 | local_namespace, global_namespace) |
| 680 | exec ("mytest = %s%s.%s(job, bindir, outputdir)" % |
| 681 | (group, testname, testname), |
| 682 | local_namespace, global_namespace) |
| 683 | finally: |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 684 | sys.path.pop(0) |
mbligh | 6231cd6 | 2008-02-02 19:18:33 +0000 | [diff] [blame] | 685 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 686 | pwd = os.getcwd() |
| 687 | os.chdir(outputdir) |
mbligh | 4395bbd | 2009-03-25 19:34:17 +0000 | [diff] [blame] | 688 | |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 689 | try: |
| 690 | mytest = global_namespace['mytest'] |
jadmanski | 30e9b59 | 2008-09-25 19:51:57 +0000 | [diff] [blame] | 691 | if before_test_hook: |
| 692 | before_test_hook(mytest) |
mbligh | 742ae42 | 2009-05-13 20:46:41 +0000 | [diff] [blame] | 693 | |
| 694 | # we use the register iteration hooks methods to register the passed |
| 695 | # in hooks |
| 696 | if before_iteration_hook: |
| 697 | mytest.register_before_iteration_hook(before_iteration_hook) |
| 698 | if after_iteration_hook: |
| 699 | mytest.register_after_iteration_hook(after_iteration_hook) |
| 700 | mytest._exec(args, dargs) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 701 | finally: |
jadmanski | 213b02b | 2008-08-26 20:51:58 +0000 | [diff] [blame] | 702 | os.chdir(pwd) |
jadmanski | 0afbb63 | 2008-06-06 21:10:57 +0000 | [diff] [blame] | 703 | if after_test_hook: |
| 704 | after_test_hook(mytest) |
jadmanski | 825e24c | 2008-08-27 20:54:31 +0000 | [diff] [blame] | 705 | shutil.rmtree(mytest.tmpdir, ignore_errors=True) |