|
25 | 25 | from domains import Domains
|
26 | 26 | from twisterlib.cmakecache import CMakeCache
|
27 | 27 | from twisterlib.environment import canonical_zephyr_base
|
28 |
| -from twisterlib.error import BuildError, ConfigurationError |
| 28 | +from twisterlib.error import BuildError, ConfigurationError, StatusAttributeError |
29 | 29 | from twisterlib.statuses import TwisterStatus
|
30 | 30 |
|
31 | 31 | import elftools
|
@@ -601,130 +601,212 @@ def log_info_file(self, inline_logs):
|
601 | 601 | self.log_info("{}".format(b_log), inline_logs)
|
602 | 602 |
|
603 | 603 |
|
| 604 | + def _add_to_pipeline(self, pipeline, op: str, additionals: dict={}): |
| 605 | + try: |
| 606 | + if op: |
| 607 | + task = dict({'op': op, 'test': self.instance}, **additionals) |
| 608 | + pipeline.put(task) |
| 609 | + # Only possible RuntimeError source here is a mutation of the pipeline during iteration. |
| 610 | + # If that happens, we ought to consider the whole pipeline corrupted. |
| 611 | + except RuntimeError as e: |
| 612 | + logger.error(f"RuntimeError: {e}") |
| 613 | + traceback.print_exc() |
| 614 | + |
| 615 | + |
604 | 616 | def process(self, pipeline, done, message, lock, results):
|
605 | 617 | op = message.get('op')
|
606 | 618 |
|
607 | 619 | self.instance.setup_handler(self.env)
|
608 | 620 |
|
609 | 621 | if op == "filter":
|
610 |
| - ret = self.cmake(filter_stages=self.instance.filter_stages) |
611 |
| - if self.instance.status in [TwisterStatus.FAIL, TwisterStatus.ERROR]: |
612 |
| - pipeline.put({"op": "report", "test": self.instance}) |
613 |
| - else: |
614 |
| - # Here we check the dt/kconfig filter results coming from running cmake |
615 |
| - if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: |
616 |
| - logger.debug("filtering %s" % self.instance.name) |
617 |
| - self.instance.status = TwisterStatus.FILTER |
618 |
| - self.instance.reason = "runtime filter" |
619 |
| - results.skipped_runtime += 1 |
620 |
| - self.instance.add_missing_case_status(TwisterStatus.SKIP) |
621 |
| - pipeline.put({"op": "report", "test": self.instance}) |
| 622 | + try: |
| 623 | + ret = self.cmake(filter_stages=self.instance.filter_stages) |
| 624 | + if self.instance.status in [TwisterStatus.FAIL, TwisterStatus.ERROR]: |
| 625 | + next_op = 'report' |
622 | 626 | else:
|
623 |
| - pipeline.put({"op": "cmake", "test": self.instance}) |
| 627 | + # Here we check the dt/kconfig filter results coming from running cmake |
| 628 | + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: |
| 629 | + logger.debug("filtering %s" % self.instance.name) |
| 630 | + self.instance.status = TwisterStatus.FILTER |
| 631 | + self.instance.reason = "runtime filter" |
| 632 | + results.skipped_runtime += 1 |
| 633 | + self.instance.add_missing_case_status(TwisterStatus.SKIP) |
| 634 | + next_op = 'report' |
| 635 | + else: |
| 636 | + next_op = 'cmake' |
| 637 | + except StatusAttributeError as sae: |
| 638 | + logger.error(str(sae)) |
| 639 | + self.instance.status = TwisterStatus.ERROR |
| 640 | + reason = 'Incorrect status assignment' |
| 641 | + self.instance.reason = reason |
| 642 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason) |
| 643 | + next_op = 'report' |
| 644 | + finally: |
| 645 | + self._add_to_pipeline(pipeline, next_op) |
624 | 646 |
|
625 | 647 | # The build process, call cmake and build with configured generator
|
626 | 648 | elif op == "cmake":
|
627 |
| - ret = self.cmake() |
628 |
| - if self.instance.status in [TwisterStatus.FAIL, TwisterStatus.ERROR]: |
629 |
| - pipeline.put({"op": "report", "test": self.instance}) |
630 |
| - elif self.options.cmake_only: |
631 |
| - if self.instance.status == TwisterStatus.NONE: |
632 |
| - self.instance.status = TwisterStatus.PASS |
633 |
| - pipeline.put({"op": "report", "test": self.instance}) |
634 |
| - else: |
635 |
| - # Here we check the runtime filter results coming from running cmake |
636 |
| - if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: |
637 |
| - logger.debug("filtering %s" % self.instance.name) |
638 |
| - self.instance.status = TwisterStatus.FILTER |
639 |
| - self.instance.reason = "runtime filter" |
640 |
| - results.skipped_runtime += 1 |
641 |
| - self.instance.add_missing_case_status(TwisterStatus.SKIP) |
642 |
| - pipeline.put({"op": "report", "test": self.instance}) |
| 649 | + try: |
| 650 | + ret = self.cmake() |
| 651 | + if self.instance.status in [TwisterStatus.FAIL, TwisterStatus.ERROR]: |
| 652 | + next_op = 'report' |
| 653 | + elif self.options.cmake_only: |
| 654 | + if self.instance.status == TwisterStatus.NONE: |
| 655 | + self.instance.status = TwisterStatus.PASS |
| 656 | + next_op = 'report' |
643 | 657 | else:
|
644 |
| - pipeline.put({"op": "build", "test": self.instance}) |
| 658 | + # Here we check the runtime filter results coming from running cmake |
| 659 | + if self.instance.name in ret['filter'] and ret['filter'][self.instance.name]: |
| 660 | + logger.debug("filtering %s" % self.instance.name) |
| 661 | + self.instance.status = TwisterStatus.FILTER |
| 662 | + self.instance.reason = "runtime filter" |
| 663 | + results.skipped_runtime += 1 |
| 664 | + self.instance.add_missing_case_status(TwisterStatus.SKIP) |
| 665 | + next_op = 'report' |
| 666 | + else: |
| 667 | + next_op = 'build' |
| 668 | + except StatusAttributeError as sae: |
| 669 | + logger.error(str(sae)) |
| 670 | + self.instance.status = TwisterStatus.ERROR |
| 671 | + reason = 'Incorrect status assignment' |
| 672 | + self.instance.reason = reason |
| 673 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason) |
| 674 | + next_op = 'report' |
| 675 | + finally: |
| 676 | + self._add_to_pipeline(pipeline, next_op) |
645 | 677 |
|
646 | 678 | elif op == "build":
|
647 |
| - logger.debug("build test: %s" % self.instance.name) |
648 |
| - ret = self.build() |
649 |
| - if not ret: |
650 |
| - self.instance.status = TwisterStatus.ERROR |
651 |
| - self.instance.reason = "Build Failure" |
652 |
| - pipeline.put({"op": "report", "test": self.instance}) |
653 |
| - else: |
654 |
| - # Count skipped cases during build, for example |
655 |
| - # due to ram/rom overflow. |
656 |
| - if self.instance.status == TwisterStatus.SKIP: |
657 |
| - results.skipped_runtime += 1 |
658 |
| - self.instance.add_missing_case_status(TwisterStatus.SKIP, self.instance.reason) |
659 |
| - |
660 |
| - if ret.get('returncode', 1) > 0: |
661 |
| - self.instance.add_missing_case_status(TwisterStatus.BLOCK, self.instance.reason) |
662 |
| - pipeline.put({"op": "report", "test": self.instance}) |
| 679 | + try: |
| 680 | + logger.debug("build test: %s" % self.instance.name) |
| 681 | + ret = self.build() |
| 682 | + if not ret: |
| 683 | + self.instance.status = TwisterStatus.ERROR |
| 684 | + self.instance.reason = "Build Failure" |
| 685 | + next_op = 'report' |
663 | 686 | else:
|
664 |
| - if self.instance.testsuite.harness in ['ztest', 'test']: |
665 |
| - logger.debug(f"Determine test cases for test instance: {self.instance.name}") |
666 |
| - try: |
667 |
| - self.determine_testcases(results) |
668 |
| - pipeline.put({"op": "gather_metrics", "test": self.instance}) |
669 |
| - except BuildError as e: |
670 |
| - logger.error(str(e)) |
671 |
| - self.instance.status = TwisterStatus.ERROR |
672 |
| - self.instance.reason = str(e) |
673 |
| - pipeline.put({"op": "report", "test": self.instance}) |
| 687 | + # Count skipped cases during build, for example |
| 688 | + # due to ram/rom overflow. |
| 689 | + if self.instance.status == TwisterStatus.SKIP: |
| 690 | + results.skipped_runtime += 1 |
| 691 | + self.instance.add_missing_case_status(TwisterStatus.SKIP, self.instance.reason) |
| 692 | + |
| 693 | + if ret.get('returncode', 1) > 0: |
| 694 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, self.instance.reason) |
| 695 | + next_op = 'report' |
674 | 696 | else:
|
675 |
| - pipeline.put({"op": "gather_metrics", "test": self.instance}) |
| 697 | + if self.instance.testsuite.harness in ['ztest', 'test']: |
| 698 | + logger.debug(f"Determine test cases for test instance: {self.instance.name}") |
| 699 | + try: |
| 700 | + self.determine_testcases(results) |
| 701 | + next_op = 'gather_metrics' |
| 702 | + except BuildError as e: |
| 703 | + logger.error(str(e)) |
| 704 | + self.instance.status = TwisterStatus.ERROR |
| 705 | + self.instance.reason = str(e) |
| 706 | + next_op = 'report' |
| 707 | + else: |
| 708 | + next_op = 'gather_metrics' |
| 709 | + except StatusAttributeError as sae: |
| 710 | + logger.error(str(sae)) |
| 711 | + self.instance.status = TwisterStatus.ERROR |
| 712 | + reason = 'Incorrect status assignment' |
| 713 | + self.instance.reason = reason |
| 714 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason) |
| 715 | + next_op = 'report' |
| 716 | + finally: |
| 717 | + self._add_to_pipeline(pipeline, next_op) |
676 | 718 |
|
677 | 719 | elif op == "gather_metrics":
|
678 |
| - ret = self.gather_metrics(self.instance) |
679 |
| - if not ret or ret.get('returncode', 1) > 0: |
| 720 | + try: |
| 721 | + ret = self.gather_metrics(self.instance) |
| 722 | + if not ret or ret.get('returncode', 1) > 0: |
| 723 | + self.instance.status = TwisterStatus.ERROR |
| 724 | + self.instance.reason = "Build Failure at gather_metrics." |
| 725 | + next_op = 'report' |
| 726 | + elif self.instance.run and self.instance.handler.ready: |
| 727 | + next_op = 'run' |
| 728 | + else: |
| 729 | + next_op = 'report' |
| 730 | + except StatusAttributeError as sae: |
| 731 | + logger.error(str(sae)) |
680 | 732 | self.instance.status = TwisterStatus.ERROR
|
681 |
| - self.instance.reason = "Build Failure at gather_metrics." |
682 |
| - pipeline.put({"op": "report", "test": self.instance}) |
683 |
| - elif self.instance.run and self.instance.handler.ready: |
684 |
| - pipeline.put({"op": "run", "test": self.instance}) |
685 |
| - else: |
686 |
| - pipeline.put({"op": "report", "test": self.instance}) |
| 733 | + reason = 'Incorrect status assignment' |
| 734 | + self.instance.reason = reason |
| 735 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason) |
| 736 | + next_op = 'report' |
| 737 | + finally: |
| 738 | + self._add_to_pipeline(pipeline, next_op) |
687 | 739 |
|
688 | 740 | # Run the generated binary using one of the supported handlers
|
689 | 741 | elif op == "run":
|
690 |
| - logger.debug("run test: %s" % self.instance.name) |
691 |
| - self.run() |
692 |
| - logger.debug(f"run status: {self.instance.name} {self.instance.status}") |
693 | 742 | try:
|
| 743 | + logger.debug("run test: %s" % self.instance.name) |
| 744 | + self.run() |
| 745 | + logger.debug(f"run status: {self.instance.name} {self.instance.status}") |
| 746 | + |
694 | 747 | # to make it work with pickle
|
695 | 748 | self.instance.handler.thread = None
|
696 | 749 | self.instance.handler.duts = None
|
697 |
| - pipeline.put({ |
698 |
| - "op": "report", |
699 |
| - "test": self.instance, |
| 750 | + |
| 751 | + next_op = 'report' |
| 752 | + additionals = { |
700 | 753 | "status": self.instance.status,
|
701 | 754 | "reason": self.instance.reason
|
702 |
| - } |
703 |
| - ) |
704 |
| - except RuntimeError as e: |
705 |
| - logger.error(f"RuntimeError: {e}") |
706 |
| - traceback.print_exc() |
| 755 | + } |
| 756 | + except StatusAttributeError as sae: |
| 757 | + logger.error(str(sae)) |
| 758 | + self.instance.status = TwisterStatus.ERROR |
| 759 | + reason = 'Incorrect status assignment' |
| 760 | + self.instance.reason = reason |
| 761 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason) |
| 762 | + next_op = 'report' |
| 763 | + additionals = {} |
| 764 | + finally: |
| 765 | + self._add_to_pipeline(pipeline, next_op, additionals) |
707 | 766 |
|
708 | 767 | # Report results and output progress to screen
|
709 | 768 | elif op == "report":
|
710 |
| - with lock: |
711 |
| - done.put(self.instance) |
712 |
| - self.report_out(results) |
713 |
| - |
714 |
| - if not self.options.coverage: |
715 |
| - if self.options.prep_artifacts_for_testing: |
716 |
| - pipeline.put({"op": "cleanup", "mode": "device", "test": self.instance}) |
717 |
| - elif self.options.runtime_artifact_cleanup == "pass" and self.instance.status == TwisterStatus.PASS: |
718 |
| - pipeline.put({"op": "cleanup", "mode": "passed", "test": self.instance}) |
719 |
| - elif self.options.runtime_artifact_cleanup == "all": |
720 |
| - pipeline.put({"op": "cleanup", "mode": "all", "test": self.instance}) |
| 769 | + try: |
| 770 | + with lock: |
| 771 | + done.put(self.instance) |
| 772 | + self.report_out(results) |
| 773 | + |
| 774 | + next_op = None |
| 775 | + additionals = {} |
| 776 | + if not self.options.coverage: |
| 777 | + if self.options.prep_artifacts_for_testing: |
| 778 | + next_op = 'cleanup' |
| 779 | + additionals = {"mode": "device"} |
| 780 | + elif self.options.runtime_artifact_cleanup == "pass" and self.instance.status == TwisterStatus.PASS: |
| 781 | + next_op = 'cleanup' |
| 782 | + additionals = {"mode": "passed"} |
| 783 | + elif self.options.runtime_artifact_cleanup == "all": |
| 784 | + next_op = 'cleanup' |
| 785 | + additionals = {"mode": "all"} |
| 786 | + except StatusAttributeError as sae: |
| 787 | + logger.error(str(sae)) |
| 788 | + self.instance.status = TwisterStatus.ERROR |
| 789 | + reason = 'Incorrect status assignment' |
| 790 | + self.instance.reason = reason |
| 791 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason) |
| 792 | + next_op = None |
| 793 | + additionals = {} |
| 794 | + finally: |
| 795 | + self._add_to_pipeline(pipeline, next_op, additionals) |
721 | 796 |
|
722 | 797 | elif op == "cleanup":
|
723 |
| - mode = message.get("mode") |
724 |
| - if mode == "device": |
725 |
| - self.cleanup_device_testing_artifacts() |
726 |
| - elif mode == "passed" or (mode == "all" and self.instance.reason != "Cmake build failure"): |
727 |
| - self.cleanup_artifacts() |
| 798 | + try: |
| 799 | + mode = message.get("mode") |
| 800 | + if mode == "device": |
| 801 | + self.cleanup_device_testing_artifacts() |
| 802 | + elif mode == "passed" or (mode == "all" and self.instance.reason != "Cmake build failure"): |
| 803 | + self.cleanup_artifacts() |
| 804 | + except StatusAttributeError as sae: |
| 805 | + logger.error(str(sae)) |
| 806 | + self.instance.status = TwisterStatus.ERROR |
| 807 | + reason = 'Incorrect status assignment' |
| 808 | + self.instance.reason = reason |
| 809 | + self.instance.add_missing_case_status(TwisterStatus.BLOCK, reason) |
728 | 810 |
|
729 | 811 | def determine_testcases(self, results):
|
730 | 812 | yaml_testsuite_name = self.instance.testsuite.id
|
|
0 commit comments