| OLD | NEW |
| 1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from datetime import datetime | 5 from datetime import datetime |
| 6 | 6 |
| 7 from common.blame import Blame | 7 from common.blame import Blame |
| 8 from common.blame import Region | 8 from common.blame import Region |
| 9 from common.change_log import FileChangeInfo | 9 from common.change_log import FileChangeInfo |
| 10 from common.diff import ChangeType | 10 from common.diff import ChangeType |
| 11 from common.git_repository import GitRepository | 11 from common.git_repository import GitRepository |
| 12 from common.waterfall import failure_type |
| 12 from waterfall import build_failure_analysis | 13 from waterfall import build_failure_analysis |
| 13 from waterfall.failure_signal import FailureSignal | 14 from waterfall.failure_signal import FailureSignal |
| 14 from waterfall.test import wf_testcase | 15 from waterfall.test import wf_testcase |
| 15 | 16 |
| 16 | 17 |
| 17 class BuildFailureAnalysisTest(wf_testcase.WaterfallTestCase): | 18 class BuildFailureAnalysisTest(wf_testcase.WaterfallTestCase): |
| 18 | 19 |
| 19 def _MockGetChangeLog(self, revision): | 20 def _MockGetChangeLog(self, revision): |
| 20 | 21 |
| 21 class MockChangeLog(object): | 22 class MockChangeLog(object): |
| (...skipping 510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 change_log_json, deps_info) | 533 change_log_json, deps_info) |
| 533 self.assertIsNotNone(justification) | 534 self.assertIsNotNone(justification) |
| 534 # The score is 1 because: | 535 # The score is 1 because: |
| 535 # +1 rolled third_party/dep1/ and src/third_party/dep1/f.cc was in log. | 536 # +1 rolled third_party/dep1/ and src/third_party/dep1/f.cc was in log. |
| 536 self.assertEqual(1, justification['score']) | 537 self.assertEqual(1, justification['score']) |
| 537 | 538 |
| 538 def testAnalyzeSuccessfulBuild(self): | 539 def testAnalyzeSuccessfulBuild(self): |
| 539 failure_info = { | 540 failure_info = { |
| 540 'failed': False, | 541 'failed': False, |
| 541 } | 542 } |
| 542 result = build_failure_analysis.AnalyzeBuildFailure( | 543 result, suspected_cls = build_failure_analysis.AnalyzeBuildFailure( |
| 543 failure_info, change_logs=None, deps_info=None, failure_signals=None) | 544 failure_info, change_logs=None, deps_info=None, failure_signals=None) |
| 544 self.assertEqual(0, len(result['failures'])) | 545 self.assertEqual(0, len(result['failures'])) |
| 546 self.assertEqual([], suspected_cls) |
| 545 | 547 |
| 546 def testAnalyzeBuildWithoutValidChromiumRevision(self): | 548 def testAnalyzeBuildWithoutValidChromiumRevision(self): |
| 547 failure_info = { | 549 failure_info = { |
| 548 'failed': True, | 550 'failed': True, |
| 549 'chromium_revision': None, | 551 'chromium_revision': None, |
| 550 } | 552 } |
| 551 result = build_failure_analysis.AnalyzeBuildFailure( | 553 result, suspected_cls = build_failure_analysis.AnalyzeBuildFailure( |
| 552 failure_info, change_logs=None, deps_info=None, failure_signals=None) | 554 failure_info, change_logs=None, deps_info=None, failure_signals=None) |
| 553 self.assertEqual(0, len(result['failures'])) | 555 self.assertEqual(0, len(result['failures'])) |
| 556 self.assertEqual([], suspected_cls) |
| 554 | 557 |
| 555 def testAnalyzeBuildFailure(self): | 558 def testAnalyzeBuildFailure(self): |
| 556 failure_info = { | 559 failure_info = { |
| 557 'master_name': 'm', | 560 'master_name': 'm', |
| 561 'builder_name': 'b', |
| 562 'build_number': 99, |
| 563 'failure_type': failure_type.TEST, |
| 558 'failed': True, | 564 'failed': True, |
| 559 'chromium_revision': 'r99_2', | 565 'chromium_revision': 'r99_2', |
| 560 'failed_steps': { | 566 'failed_steps': { |
| 561 'a': { | 567 'a': { |
| 562 'current_failure': 99, | 568 'current_failure': 99, |
| 563 'first_failure': 98, | 569 'first_failure': 98, |
| 564 }, | 570 }, |
| 565 'b': { | 571 'b': { |
| 566 'current_failure': 99, | 572 'current_failure': 99, |
| 567 'first_failure': 98, | 573 'first_failure': 98, |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 'score': 5, | 695 'score': 5, |
| 690 'hints': { | 696 'hints': { |
| 691 'added x/y/f99_1.cc (and it was in log)': 5, | 697 'added x/y/f99_1.cc (and it was in log)': 5, |
| 692 }, | 698 }, |
| 693 } | 699 } |
| 694 ], | 700 ], |
| 695 } | 701 } |
| 696 ] | 702 ] |
| 697 } | 703 } |
| 698 | 704 |
| 699 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | 705 expected_suspected_cl = [ |
| 706 { |
| 707 'repo_name': 'chromium', |
| 708 'revision': 'r99_2', |
| 709 'commit_position': None, |
| 710 'url': None, |
| 711 'failures': { |
| 712 'a': [] |
| 713 }, |
| 714 'top_score': 2 |
| 715 }, |
| 716 { |
| 717 'repo_name': 'chromium', |
| 718 'revision': 'r97_1', |
| 719 'commit_position': None, |
| 720 'url': None, |
| 721 'failures': { |
| 722 'b': [] |
| 723 }, |
| 724 'top_score': 5 |
| 725 } |
| 726 ] |
| 727 |
| 728 analysis_result, suspected_cls = build_failure_analysis.AnalyzeBuildFailure( |
| 700 failure_info, change_logs, deps_info, failure_signals_json) | 729 failure_info, change_logs, deps_info, failure_signals_json) |
| 730 |
| 701 self.assertEqual(expected_analysis_result, analysis_result) | 731 self.assertEqual(expected_analysis_result, analysis_result) |
| 732 self.assertEqual(sorted(expected_suspected_cl), sorted(suspected_cls)) |
| 702 | 733 |
| 703 def testAnalyzeBuildFailureTestLevel(self): | 734 def testAnalyzeBuildFailureTestLevel(self): |
| 704 failure_info = { | 735 failure_info = { |
| 705 'failed': True, | 736 'failed': True, |
| 706 'chromium_revision': 'r99_2', | 737 'chromium_revision': 'r99_2', |
| 707 'master_name': 'm', | 738 'master_name': 'm', |
| 739 'builder_name': 'b', |
| 740 'build_number': 99, |
| 741 'failure_type': failure_type.TEST, |
| 708 'failed_steps': { | 742 'failed_steps': { |
| 709 'a': { | 743 'a': { |
| 710 'current_failure': 99, | 744 'current_failure': 99, |
| 711 'first_failure': 98, | 745 'first_failure': 98, |
| 712 }, | 746 }, |
| 713 'b': { | 747 'b': { |
| 714 'current_failure': 99, | 748 'current_failure': 99, |
| 715 'first_failure': 98, | 749 'first_failure': 98, |
| 716 'last_pass': 96, | 750 'last_pass': 96, |
| 717 'list_isolated_data': [ | 751 'list_isolated_data': [ |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 968 'test_name': 'Unittest3.Subtest3', | 1002 'test_name': 'Unittest3.Subtest3', |
| 969 'first_failure': 98, | 1003 'first_failure': 98, |
| 970 'last_pass': 96, | 1004 'last_pass': 96, |
| 971 'suspected_cls': [] | 1005 'suspected_cls': [] |
| 972 } | 1006 } |
| 973 ] | 1007 ] |
| 974 } | 1008 } |
| 975 ] | 1009 ] |
| 976 } | 1010 } |
| 977 | 1011 |
| 978 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | 1012 expected_suspected_cl = [ |
| 1013 { |
| 1014 'repo_name': 'chromium', |
| 1015 'revision': 'r99_2', |
| 1016 'commit_position': None, |
| 1017 'url': None, |
| 1018 'failures': { |
| 1019 'a': [] |
| 1020 }, |
| 1021 'top_score': 2 |
| 1022 }, |
| 1023 { |
| 1024 'repo_name': 'chromium', |
| 1025 'revision': 'r97_1', |
| 1026 'commit_position': None, |
| 1027 'url': None, |
| 1028 'failures': { |
| 1029 'b': ['Unittest1.Subtest1'] |
| 1030 }, |
| 1031 'top_score': 5 |
| 1032 }, |
| 1033 { |
| 1034 'repo_name': 'chromium', |
| 1035 'revision': 'r98_1', |
| 1036 'commit_position': None, |
| 1037 'url': None, |
| 1038 'failures': { |
| 1039 'b': ['Unittest2.Subtest1', 'Unittest3.Subtest2'] |
| 1040 }, |
| 1041 'top_score': 4 |
| 1042 } |
| 1043 ] |
| 1044 |
| 1045 analysis_result, suspected_cls = build_failure_analysis.AnalyzeBuildFailure( |
| 979 failure_info, change_logs, deps_info, failure_signals_json) | 1046 failure_info, change_logs, deps_info, failure_signals_json) |
| 980 | 1047 |
| 981 self.assertEqual(expected_analysis_result, analysis_result) | 1048 self.assertEqual(expected_analysis_result, analysis_result) |
| 1049 self.assertEqual(sorted(expected_suspected_cl), sorted(suspected_cls)) |
| 982 | 1050 |
| 983 def testAnalyzeBuildFailureForUnsupportedStep(self): | 1051 def testAnalyzeBuildFailureForUnsupportedStep(self): |
| 984 failure_info = { | 1052 failure_info = { |
| 985 'master_name': 'master1', | 1053 'master_name': 'master1', |
| 1054 'builder_name': 'b', |
| 1055 'build_number': 99, |
| 1056 'failure_type': failure_type.TEST, |
| 986 'failed': True, | 1057 'failed': True, |
| 987 'chromium_revision': 'r99_2', | 1058 'chromium_revision': 'r99_2', |
| 988 'failed_steps': { | 1059 'failed_steps': { |
| 989 'unsupported_step1': { | 1060 'unsupported_step1': { |
| 990 'current_failure': 99, | 1061 'current_failure': 99, |
| 991 'first_failure': 98, | 1062 'first_failure': 98, |
| 992 }, | 1063 }, |
| 993 }, | 1064 }, |
| 994 'builds': { | 1065 'builds': { |
| 995 '99': { | 1066 '99': { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1014 { | 1085 { |
| 1015 'step_name': 'unsupported_step1', | 1086 'step_name': 'unsupported_step1', |
| 1016 'supported': False, | 1087 'supported': False, |
| 1017 'first_failure': 98, | 1088 'first_failure': 98, |
| 1018 'last_pass': None, | 1089 'last_pass': None, |
| 1019 'suspected_cls': [], | 1090 'suspected_cls': [], |
| 1020 }, | 1091 }, |
| 1021 ] | 1092 ] |
| 1022 } | 1093 } |
| 1023 | 1094 |
| 1024 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | 1095 analysis_result, suspected_cls = build_failure_analysis.AnalyzeBuildFailure( |
| 1025 failure_info, change_logs, deps_info, failure_signals_json) | 1096 failure_info, change_logs, deps_info, failure_signals_json) |
| 1026 self.assertEqual(expected_analysis_result, analysis_result) | 1097 self.assertEqual(expected_analysis_result, analysis_result) |
| 1098 self.assertEqual([], suspected_cls) |
| 1027 | 1099 |
| 1028 def testGetGitBlame(self): | 1100 def testGetGitBlame(self): |
| 1029 repo_info = { | 1101 repo_info = { |
| 1030 'repo_url': 'https://chromium.googlesource.com/chromium/src.git', | 1102 'repo_url': 'https://chromium.googlesource.com/chromium/src.git', |
| 1031 'revision': '8' | 1103 'revision': '8' |
| 1032 } | 1104 } |
| 1033 file_path = 'a/b/c.cc' | 1105 file_path = 'a/b/c.cc' |
| 1034 self.mock(GitRepository, 'GetBlame', self._MockGetBlame) | 1106 self.mock(GitRepository, 'GetBlame', self._MockGetBlame) |
| 1035 blame = build_failure_analysis._GetGitBlame(repo_info, file_path) | 1107 blame = build_failure_analysis._GetGitBlame(repo_info, file_path) |
| 1036 self.assertIsNotNone(blame) | 1108 self.assertIsNotNone(blame) |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1141 touched_file, file_path_in_log, justification, file_name_occurrences, | 1213 touched_file, file_path_in_log, justification, file_name_occurrences, |
| 1142 line_numbers, repo_info, commit_revision) | 1214 line_numbers, repo_info, commit_revision) |
| 1143 | 1215 |
| 1144 expected_justification = { | 1216 expected_justification = { |
| 1145 'score': 4, | 1217 'score': 4, |
| 1146 'hints': { | 1218 'hints': { |
| 1147 'modified c.cc[1, 3] (and it was in log)': 4 | 1219 'modified c.cc[1, 3] (and it was in log)': 4 |
| 1148 } | 1220 } |
| 1149 } | 1221 } |
| 1150 self.assertEqual(expected_justification, justification.ToDict()) | 1222 self.assertEqual(expected_justification, justification.ToDict()) |
| OLD | NEW |