OLD | NEW |
1 """The main job wrapper | 1 """The main job wrapper |
2 | 2 |
3 This is the core infrastructure. | 3 This is the core infrastructure. |
4 | 4 |
5 Copyright Andy Whitcroft, Martin J. Bligh 2006 | 5 Copyright Andy Whitcroft, Martin J. Bligh 2006 |
6 """ | 6 """ |
7 | 7 |
8 import copy, os, platform, re, shutil, sys, time, traceback, types, glob | 8 import copy, os, platform, re, shutil, sys, time, traceback, types, glob |
9 import logging, getpass, errno, weakref | 9 import logging, getpass, errno, weakref |
10 import cPickle as pickle | 10 import cPickle as pickle |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 | 186 |
187 # set up the status logger | 187 # set up the status logger |
188 def client_job_record_hook(entry): | 188 def client_job_record_hook(entry): |
189 msg_tag = '' | 189 msg_tag = '' |
190 if '.' in self._logger.global_filename: | 190 if '.' in self._logger.global_filename: |
191 msg_tag = self._logger.global_filename.split('.', 1)[1] | 191 msg_tag = self._logger.global_filename.split('.', 1)[1] |
192 # send the entry to the job harness | 192 # send the entry to the job harness |
193 message = '\n'.join([entry.message] + entry.extra_message_lines) | 193 message = '\n'.join([entry.message] + entry.extra_message_lines) |
194 rendered_entry = self._logger.render_entry(entry) | 194 rendered_entry = self._logger.render_entry(entry) |
195 self.harness.test_status_detail(entry.status_code, entry.subdir, | 195 self.harness.test_status_detail(entry.status_code, entry.subdir, |
196 entry.operation, message, msg_tag) | 196 entry.operation, message, msg_tag, |
| 197 entry.fields) |
197 self.harness.test_status(rendered_entry, msg_tag) | 198 self.harness.test_status(rendered_entry, msg_tag) |
198 # send the entry to stdout, if it's enabled | 199 # send the entry to stdout, if it's enabled |
199 logging.info(rendered_entry) | 200 logging.info(rendered_entry) |
200 self._logger = base_job.status_logger( | 201 self._logger = base_job.status_logger( |
201 self, status_indenter(self), record_hook=client_job_record_hook, | 202 self, status_indenter(self), record_hook=client_job_record_hook, |
202 tap_writer=self._tap) | 203 tap_writer=self._tap) |
203 | 204 |
204 def _post_record_init(self, control, options, drop_caches, | 205 def _post_record_init(self, control, options, drop_caches, |
205 extra_copy_cmdline): | 206 extra_copy_cmdline): |
206 """ | 207 """ |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 | 509 |
509 # dep_dir might not exist if it is not fetched from the repos | 510 # dep_dir might not exist if it is not fetched from the repos |
510 if not os.path.exists(dep_dir): | 511 if not os.path.exists(dep_dir): |
511 raise error.TestError("Dependency %s does not exist" % dep) | 512 raise error.TestError("Dependency %s does not exist" % dep) |
512 | 513 |
513 os.chdir(dep_dir) | 514 os.chdir(dep_dir) |
514 if execfile('%s.py' % dep, {}) is None: | 515 if execfile('%s.py' % dep, {}) is None: |
515 logging.info('Dependency %s successfuly built', dep) | 516 logging.info('Dependency %s successfuly built', dep) |
516 | 517 |
517 | 518 |
518 def _runtest(self, url, tag, args, dargs): | 519 def _runtest(self, url, tag, timeout, args, dargs): |
519 try: | 520 try: |
520 l = lambda : test.runtest(self, url, tag, args, dargs) | 521 l = lambda : test.runtest(self, url, tag, args, dargs) |
521 pid = parallel.fork_start(self.resultdir, l) | 522 pid = parallel.fork_start(self.resultdir, l) |
522 parallel.fork_waitfor(self.resultdir, pid) | 523 |
| 524 if timeout: |
| 525 logging.debug('Waiting for pid %d for %d seconds', pid, timeout) |
| 526 parallel.fork_waitfor_timed(self.resultdir, pid, timeout) |
| 527 else: |
| 528 parallel.fork_waitfor(self.resultdir, pid) |
| 529 |
523 except error.TestBaseException: | 530 except error.TestBaseException: |
524 # These are already classified with an error type (exit_status) | 531 # These are already classified with an error type (exit_status) |
525 raise | 532 raise |
526 except error.JobError: | 533 except error.JobError: |
527 raise # Caught further up and turned into an ABORT. | 534 raise # Caught further up and turned into an ABORT. |
528 except Exception, e: | 535 except Exception, e: |
529 # Converts all other exceptions thrown by the test regardless | 536 # Converts all other exceptions thrown by the test regardless |
530 # of phase into a TestError(TestBaseException) subclass that | 537 # of phase into a TestError(TestBaseException) subclass that |
531 # reports them with their full stack trace. | 538 # reports them with their full stack trace. |
532 raise error.UnhandledTestError(e) | 539 raise error.UnhandledTestError(e) |
533 | 540 |
534 | 541 |
535 @_run_test_complete_on_exit | 542 def _run_test_base(self, url, *args, **dargs): |
536 def run_test(self, url, *args, **dargs): | |
537 """ | 543 """ |
538 Summon a test object and run it. | 544 Prepares arguments and run functions to run_test and run_test_detail. |
539 | 545 |
540 @param url A url that identifies the test to run. | 546 @param url A url that identifies the test to run. |
541 @param tag An optional keyword argument that will be added to the | 547 @param tag An optional keyword argument that will be added to the |
542 test and subdir name. | 548 test and subdir name. |
543 @param subdir_tag An optional keyword argument that will be added | 549 @param subdir_tag An optional keyword argument that will be added |
544 to the subdir name. | 550 to the subdir name. |
545 | 551 |
546 @returns True if the test passes, False otherwise. | 552 @returns: |
| 553 subdir: Test subdirectory |
| 554 testname: Test name |
| 555 group_func: Actual test run function |
| 556 timeout: Test timeout |
547 """ | 557 """ |
548 group, testname = self.pkgmgr.get_package_name(url, 'test') | 558 group, testname = self.pkgmgr.get_package_name(url, 'test') |
549 testname, subdir, tag = self._build_tagged_test_name(testname, dargs) | 559 testname, subdir, tag = self._build_tagged_test_name(testname, dargs) |
550 outputdir = self._make_test_outputdir(subdir) | 560 outputdir = self._make_test_outputdir(subdir) |
551 | 561 |
| 562 timeout = dargs.pop('timeout', None) |
| 563 if timeout: |
| 564 logging.debug('Test has timeout: %d sec.', timeout) |
| 565 |
552 def log_warning(reason): | 566 def log_warning(reason): |
553 self.record("WARN", subdir, testname, reason) | 567 self.record("WARN", subdir, testname, reason) |
554 @disk_usage_monitor.watch(log_warning, "/", self._max_disk_usage_rate) | 568 @disk_usage_monitor.watch(log_warning, "/", self._max_disk_usage_rate) |
555 def group_func(): | 569 def group_func(): |
556 try: | 570 try: |
557 self._runtest(url, tag, args, dargs) | 571 self._runtest(url, tag, timeout, args, dargs) |
558 except error.TestBaseException, detail: | 572 except error.TestBaseException, detail: |
559 # The error is already classified, record it properly. | 573 # The error is already classified, record it properly. |
560 self.record(detail.exit_status, subdir, testname, str(detail)) | 574 self.record(detail.exit_status, subdir, testname, str(detail)) |
561 raise | 575 raise |
562 else: | 576 else: |
563 self.record('GOOD', subdir, testname, 'completed successfully') | 577 self.record('GOOD', subdir, testname, 'completed successfully') |
564 | 578 |
| 579 return (subdir, testname, group_func, timeout) |
| 580 |
| 581 |
| 582 @_run_test_complete_on_exit |
| 583 def run_test(self, url, *args, **dargs): |
| 584 """ |
| 585 Summon a test object and run it. |
| 586 |
| 587 @param url A url that identifies the test to run. |
| 588 @param tag An optional keyword argument that will be added to the |
| 589 test and subdir name. |
| 590 @param subdir_tag An optional keyword argument that will be added |
| 591 to the subdir name. |
| 592 |
| 593 @returns True if the test passes, False otherwise. |
| 594 """ |
| 595 (subdir, testname, group_func, timeout) = self._run_test_base(url, |
| 596 *args, |
| 597 **dargs) |
565 try: | 598 try: |
566 self._rungroup(subdir, testname, group_func) | 599 self._rungroup(subdir, testname, group_func, timeout) |
567 return True | 600 return True |
568 except error.TestBaseException: | 601 except error.TestBaseException: |
569 return False | 602 return False |
570 # Any other exception here will be given to the caller | 603 # Any other exception here will be given to the caller |
571 # | 604 # |
572 # NOTE: The only exception possible from the control file here | 605 # NOTE: The only exception possible from the control file here |
573 # is error.JobError as _runtest() turns all others into an | 606 # is error.JobError as _runtest() turns all others into an |
574 # UnhandledTestError that is caught above. | 607 # UnhandledTestError that is caught above. |
575 | 608 |
576 | 609 |
577 def _rungroup(self, subdir, testname, function, *args, **dargs): | 610 @_run_test_complete_on_exit |
| 611 def run_test_detail(self, url, *args, **dargs): |
| 612 """ |
| 613 Summon a test object and run it, returning test status. |
| 614 |
| 615 @param url A url that identifies the test to run. |
| 616 @param tag An optional keyword argument that will be added to the |
| 617 test and subdir name. |
| 618 @param subdir_tag An optional keyword argument that will be added |
| 619 to the subdir name. |
| 620 |
| 621 @returns Test status |
| 622 @see: client/common_lib/error.py, exit_status |
| 623 """ |
| 624 (subdir, testname, group_func, timeout) = self._run_test_base(url, |
| 625 *args, |
| 626 **dargs) |
| 627 try: |
| 628 self._rungroup(subdir, testname, group_func, timeout) |
| 629 return 'GOOD' |
| 630 except error.TestBaseException, detail: |
| 631 return detail.exit_status |
| 632 |
| 633 |
| 634 def _rungroup(self, subdir, testname, function, timeout, *args, **dargs): |
578 """\ | 635 """\ |
579 subdir: | 636 subdir: |
580 name of the group | 637 name of the group |
581 testname: | 638 testname: |
582 name of the test to run, or support step | 639 name of the test to run, or support step |
583 function: | 640 function: |
584 subroutine to run | 641 subroutine to run |
585 *args: | 642 *args: |
586 arguments for the function | 643 arguments for the function |
587 | 644 |
588 Returns the result of the passed in function | 645 Returns the result of the passed in function |
589 """ | 646 """ |
590 | 647 |
591 try: | 648 try: |
592 self.record('START', subdir, testname) | 649 optional_fields = None |
| 650 if timeout: |
| 651 optional_fields = {} |
| 652 optional_fields['timeout'] = timeout |
| 653 self.record('START', subdir, testname, |
| 654 optional_fields=optional_fields) |
| 655 |
593 self._state.set('client', 'unexpected_reboot', (subdir, testname)) | 656 self._state.set('client', 'unexpected_reboot', (subdir, testname)) |
594 try: | 657 try: |
595 result = function(*args, **dargs) | 658 result = function(*args, **dargs) |
596 self.record('END GOOD', subdir, testname) | 659 self.record('END GOOD', subdir, testname) |
597 return result | 660 return result |
598 except error.TestBaseException, e: | 661 except error.TestBaseException, e: |
599 self.record('END %s' % e.exit_status, subdir, testname) | 662 self.record('END %s' % e.exit_status, subdir, testname) |
600 raise | 663 raise |
601 except error.JobError, e: | 664 except error.JobError, e: |
602 self.record('END ABORT', subdir, testname) | 665 self.record('END ABORT', subdir, testname) |
(...skipping 23 matching lines...) Expand all Loading... |
626 **dargs: | 689 **dargs: |
627 Named arguments for the function. | 690 Named arguments for the function. |
628 """ | 691 """ |
629 if tag: | 692 if tag: |
630 name = tag | 693 name = tag |
631 else: | 694 else: |
632 name = function.__name__ | 695 name = function.__name__ |
633 | 696 |
634 try: | 697 try: |
635 return self._rungroup(subdir=None, testname=name, | 698 return self._rungroup(subdir=None, testname=name, |
636 function=function, **dargs) | 699 function=function, timeout=None, **dargs) |
637 except (SystemExit, error.TestBaseException): | 700 except (SystemExit, error.TestBaseException): |
638 raise | 701 raise |
639 # If there was a different exception, turn it into a TestError. | 702 # If there was a different exception, turn it into a TestError. |
640 # It will be caught by step_engine or _run_step_fn. | 703 # It will be caught by step_engine or _run_step_fn. |
641 except Exception, e: | 704 except Exception, e: |
642 raise error.UnhandledTestError(e) | 705 raise error.UnhandledTestError(e) |
643 | 706 |
644 | 707 |
645 def cpu_count(self): | 708 def cpu_count(self): |
646 return utils.count_cpus() # use total system count | 709 return utils.count_cpus() # use total system count |
(...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1258 assert myjob._record_indent == 0 | 1321 assert myjob._record_indent == 0 |
1259 | 1322 |
1260 myjob.complete(0) | 1323 myjob.complete(0) |
1261 | 1324 |
1262 | 1325 |
1263 site_job = utils.import_site_class( | 1326 site_job = utils.import_site_class( |
1264 __file__, "autotest_lib.client.bin.site_job", "site_job", base_client_job) | 1327 __file__, "autotest_lib.client.bin.site_job", "site_job", base_client_job) |
1265 | 1328 |
1266 class job(site_job): | 1329 class job(site_job): |
1267 pass | 1330 pass |
OLD | NEW |