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