| 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 testing_utils import testing | |
| 8 | |
| 9 from common.blame import Blame | 7 from common.blame import Blame |
| 10 from common.blame import Region | 8 from common.blame import Region |
| 11 from common.change_log import FileChangeInfo | 9 from common.change_log import FileChangeInfo |
| 12 from common.diff import ChangeType | 10 from common.diff import ChangeType |
| 13 from common.git_repository import GitRepository | 11 from common.git_repository import GitRepository |
| 14 from waterfall import build_failure_analysis | 12 from waterfall import build_failure_analysis |
| 15 from waterfall import waterfall_config | |
| 16 from waterfall.failure_signal import FailureSignal | 13 from waterfall.failure_signal import FailureSignal |
| 14 from waterfall.test import wf_configured_test_case |
| 17 | 15 |
| 18 | 16 |
| 19 class BuildFailureAnalysisTest(testing.AppengineTestCase): | 17 class BuildFailureAnalysisTest(wf_configured_test_case.WaterfallTestCase): |
| 20 | 18 |
| 21 def _MockGetChangeLog(self, revision): | 19 def _MockGetChangeLog(self, revision): |
| 22 | 20 |
| 23 class MockChangeLog(object): | 21 class MockChangeLog(object): |
| 24 | 22 |
| 25 def __init__(self, date, touched_files): | 23 def __init__(self, date, touched_files): |
| 26 self.author_time = datetime.strptime( | 24 self.author_time = datetime.strptime( |
| 27 'Jun %s 04:35:32 2015' % date, '%b %d %H:%M:%S %Y') | 25 'Jun %s 04:35:32 2015' % date, '%b %d %H:%M:%S %Y') |
| 28 self.touched_files = touched_files | 26 self.touched_files = touched_files |
| 29 | 27 |
| (...skipping 519 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 549 failure_info = { | 547 failure_info = { |
| 550 'failed': True, | 548 'failed': True, |
| 551 'chromium_revision': None, | 549 'chromium_revision': None, |
| 552 } | 550 } |
| 553 result = build_failure_analysis.AnalyzeBuildFailure( | 551 result = build_failure_analysis.AnalyzeBuildFailure( |
| 554 failure_info, change_logs=None, deps_info=None, failure_signals=None) | 552 failure_info, change_logs=None, deps_info=None, failure_signals=None) |
| 555 self.assertEqual(0, len(result['failures'])) | 553 self.assertEqual(0, len(result['failures'])) |
| 556 | 554 |
| 557 def testAnalyzeBuildFailure(self): | 555 def testAnalyzeBuildFailure(self): |
| 558 failure_info = { | 556 failure_info = { |
| 559 'master_name': 'blabla', | 557 'master_name': 'm', |
| 560 'failed': True, | 558 'failed': True, |
| 561 'chromium_revision': 'r99_2', | 559 'chromium_revision': 'r99_2', |
| 562 'failed_steps': { | 560 'failed_steps': { |
| 563 'a': { | 561 'a': { |
| 564 'current_failure': 99, | 562 'current_failure': 99, |
| 565 'first_failure': 98, | 563 'first_failure': 98, |
| 566 }, | 564 }, |
| 567 'b': { | 565 'b': { |
| 568 'current_failure': 99, | 566 'current_failure': 99, |
| 569 'first_failure': 98, | 567 'first_failure': 98, |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 691 'score': 5, | 689 'score': 5, |
| 692 'hints': { | 690 'hints': { |
| 693 'added x/y/f99_1.cc (and it was in log)': 5, | 691 'added x/y/f99_1.cc (and it was in log)': 5, |
| 694 }, | 692 }, |
| 695 } | 693 } |
| 696 ], | 694 ], |
| 697 } | 695 } |
| 698 ] | 696 ] |
| 699 } | 697 } |
| 700 | 698 |
| 701 def MockStepIsSupportedForMaster(*_): | |
| 702 return True | |
| 703 self.mock(waterfall_config, 'StepIsSupportedForMaster', | |
| 704 MockStepIsSupportedForMaster) | |
| 705 | |
| 706 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | 699 analysis_result = build_failure_analysis.AnalyzeBuildFailure( |
| 707 failure_info, change_logs, deps_info, failure_signals_json) | 700 failure_info, change_logs, deps_info, failure_signals_json) |
| 708 self.assertEqual(expected_analysis_result, analysis_result) | 701 self.assertEqual(expected_analysis_result, analysis_result) |
| 709 | 702 |
| 710 def testAnalyzeBuildFailureTestLevel(self): | 703 def testAnalyzeBuildFailureTestLevel(self): |
| 711 failure_info = { | 704 failure_info = { |
| 712 'failed': True, | 705 'failed': True, |
| 713 'chromium_revision': 'r99_2', | 706 'chromium_revision': 'r99_2', |
| 707 'master_name': 'm', |
| 714 'failed_steps': { | 708 'failed_steps': { |
| 715 'a': { | 709 'a': { |
| 716 'current_failure': 99, | 710 'current_failure': 99, |
| 717 'first_failure': 98, | 711 'first_failure': 98, |
| 718 }, | 712 }, |
| 719 'b': { | 713 'b': { |
| 720 'current_failure': 99, | 714 'current_failure': 99, |
| 721 'first_failure': 98, | 715 'first_failure': 98, |
| 722 'last_pass': 96, | 716 'last_pass': 96, |
| 723 'list_isolated_data': [ | 717 'list_isolated_data': [ |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 }, | 842 }, |
| 849 'Unittest3.Subtest2': { | 843 'Unittest3.Subtest2': { |
| 850 'files': { | 844 'files': { |
| 851 'y/z/f98.cc': [456], | 845 'y/z/f98.cc': [456], |
| 852 }, | 846 }, |
| 853 } | 847 } |
| 854 } | 848 } |
| 855 } | 849 } |
| 856 } | 850 } |
| 857 | 851 |
| 858 def MockStepIsSupportedForMaster(*_): | |
| 859 return True | |
| 860 self.mock(waterfall_config, 'StepIsSupportedForMaster', | |
| 861 MockStepIsSupportedForMaster) | |
| 862 | |
| 863 def MockGetChangedLines(repo_info, touched_file, line_numbers, _): | 852 def MockGetChangedLines(repo_info, touched_file, line_numbers, _): |
| 864 # Only need line_numbers, ignoring the first two parameters. | 853 # Only need line_numbers, ignoring the first two parameters. |
| 865 del repo_info, touched_file | 854 del repo_info, touched_file |
| 866 if line_numbers: | 855 if line_numbers: |
| 867 return line_numbers | 856 return line_numbers |
| 868 self.mock(build_failure_analysis, '_GetChangedLinesForChromiumRepo', | 857 self.mock(build_failure_analysis, '_GetChangedLinesForChromiumRepo', |
| 869 MockGetChangedLines) | 858 MockGetChangedLines) |
| 870 | 859 |
| 871 expected_analysis_result = { | 860 expected_analysis_result = { |
| 872 'failures': [ | 861 'failures': [ |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 986 ] | 975 ] |
| 987 } | 976 } |
| 988 | 977 |
| 989 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | 978 analysis_result = build_failure_analysis.AnalyzeBuildFailure( |
| 990 failure_info, change_logs, deps_info, failure_signals_json) | 979 failure_info, change_logs, deps_info, failure_signals_json) |
| 991 | 980 |
| 992 self.assertEqual(expected_analysis_result, analysis_result) | 981 self.assertEqual(expected_analysis_result, analysis_result) |
| 993 | 982 |
| 994 def testAnalyzeBuildFailureForUnsupportedStep(self): | 983 def testAnalyzeBuildFailureForUnsupportedStep(self): |
| 995 failure_info = { | 984 failure_info = { |
| 996 'master_name': 'm', | 985 'master_name': 'master1', |
| 997 'failed': True, | 986 'failed': True, |
| 998 'chromium_revision': 'r99_2', | 987 'chromium_revision': 'r99_2', |
| 999 'failed_steps': { | 988 'failed_steps': { |
| 1000 'not_supported': { | 989 'unsupported_step1': { |
| 1001 'current_failure': 99, | 990 'current_failure': 99, |
| 1002 'first_failure': 98, | 991 'first_failure': 98, |
| 1003 }, | 992 }, |
| 1004 }, | 993 }, |
| 1005 'builds': { | 994 'builds': { |
| 1006 '99': { | 995 '99': { |
| 1007 'blame_list': ['r99_1', 'r99_2'], | 996 'blame_list': ['r99_1', 'r99_2'], |
| 1008 }, | 997 }, |
| 1009 '98': { | 998 '98': { |
| 1010 'blame_list': ['r98_1'], | 999 'blame_list': ['r98_1'], |
| 1011 }, | 1000 }, |
| 1012 } | 1001 } |
| 1013 } | 1002 } |
| 1014 change_logs = {} | 1003 change_logs = {} |
| 1015 deps_info = {} | 1004 deps_info = {} |
| 1016 failure_signals_json = { | 1005 failure_signals_json = { |
| 1017 'not_supported': { | 1006 'not_supported': { |
| 1018 'files': { | 1007 'files': { |
| 1019 'src/a/b/f99_2.cc': [], | 1008 'src/a/b/f99_2.cc': [], |
| 1020 }, | 1009 }, |
| 1021 } | 1010 } |
| 1022 } | 1011 } |
| 1023 expected_analysis_result = { | 1012 expected_analysis_result = { |
| 1024 'failures': [ | 1013 'failures': [ |
| 1025 { | 1014 { |
| 1026 'step_name': 'not_supported', | 1015 'step_name': 'unsupported_step1', |
| 1027 'supported': False, | 1016 'supported': False, |
| 1028 'first_failure': 98, | 1017 'first_failure': 98, |
| 1029 'last_pass': None, | 1018 'last_pass': None, |
| 1030 'suspected_cls': [], | 1019 'suspected_cls': [], |
| 1031 }, | 1020 }, |
| 1032 ] | 1021 ] |
| 1033 } | 1022 } |
| 1034 | 1023 |
| 1035 def MockStepIsSupportedForMaster(*_): | |
| 1036 return False | |
| 1037 self.mock(waterfall_config, 'StepIsSupportedForMaster', | |
| 1038 MockStepIsSupportedForMaster) | |
| 1039 | |
| 1040 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | 1024 analysis_result = build_failure_analysis.AnalyzeBuildFailure( |
| 1041 failure_info, change_logs, deps_info, failure_signals_json) | 1025 failure_info, change_logs, deps_info, failure_signals_json) |
| 1042 self.assertEqual(expected_analysis_result, analysis_result) | 1026 self.assertEqual(expected_analysis_result, analysis_result) |
| 1043 | 1027 |
| 1044 def testGetGitBlame(self): | 1028 def testGetGitBlame(self): |
| 1045 repo_info = { | 1029 repo_info = { |
| 1046 'repo_url': 'https://chromium.googlesource.com/chromium/src.git', | 1030 'repo_url': 'https://chromium.googlesource.com/chromium/src.git', |
| 1047 'revision': '8' | 1031 'revision': '8' |
| 1048 } | 1032 } |
| 1049 file_path = 'a/b/c.cc' | 1033 file_path = 'a/b/c.cc' |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1157 touched_file, file_path_in_log, justification, file_name_occurrences, | 1141 touched_file, file_path_in_log, justification, file_name_occurrences, |
| 1158 line_numbers, repo_info, commit_revision) | 1142 line_numbers, repo_info, commit_revision) |
| 1159 | 1143 |
| 1160 expected_justification = { | 1144 expected_justification = { |
| 1161 'score': 4, | 1145 'score': 4, |
| 1162 'hints': { | 1146 'hints': { |
| 1163 'modified c.cc[1, 3] (and it was in log)': 4 | 1147 'modified c.cc[1, 3] (and it was in log)': 4 |
| 1164 } | 1148 } |
| 1165 } | 1149 } |
| 1166 self.assertEqual(expected_justification, justification.ToDict()) | 1150 self.assertEqual(expected_justification, justification.ToDict()) |
| OLD | NEW |