Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import unittest | |
| 6 | |
| 7 from common.diff import ChangeType | |
| 8 from waterfall import build_failure_analysis | |
| 9 from waterfall.failure_signal import FailureSignal | |
| 10 | |
| 11 | |
| 12 class BuildFailureAnalysisTest(unittest.TestCase): | |
| 13 | |
| 14 def testIsSameFile(self): | |
| 15 self.assertTrue(build_failure_analysis.IsSameFile('a/b/x.cc', 'x.cc')) | |
| 16 self.assertFalse(build_failure_analysis.IsSameFile('a/b/pre_x.cc.', 'x.cc')) | |
| 17 self.assertFalse(build_failure_analysis.IsSameFile('a/b/x.cc.', 'a/b/y.cc')) | |
| 18 | |
| 19 def testJoinAsFilePath(self): | |
| 20 self.assertEqual('a/x.cc', | |
| 21 build_failure_analysis.JoinAsFilePath('a', 'x.cc')) | |
| 22 self.assertEqual('x.cc', | |
| 23 build_failure_analysis.JoinAsFilePath(None, 'x.cc')) | |
| 24 | |
| 25 def testNormalizeObjectFile(self): | |
| 26 cases = { | |
| 27 'obj/a/T.x.o': 'a/x.o', | |
| 28 'obj/a/T.x.y.o': 'a/x.y.o', | |
| 29 'x.o': 'x.o' | |
| 30 } | |
| 31 for obj_file, expected_file in cases.iteritems(): | |
| 32 self.assertEqual( | |
| 33 expected_file, | |
| 34 build_failure_analysis.NormalizeObjectFile(obj_file)) | |
| 35 | |
| 36 def testStripCommonPostfix(self): | |
| 37 cases = { | |
| 38 'a_file': | |
| 39 'a_file_%s.cc' % '_'.join(build_failure_analysis.COMMON_POSTFIXES), | |
| 40 'src/b_file': 'src/b_file_impl_mac.h', | |
| 41 'c_file': 'c_file_browsertest.cc' | |
| 42 } | |
| 43 for expected_file, file_path in cases.iteritems(): | |
| 44 self.assertEqual( | |
| 45 expected_file, | |
| 46 build_failure_analysis.StripExtensionAndCommonPostfix(file_path)) | |
| 47 | |
| 48 def testIsCorrelated(self): | |
| 49 self.assertTrue(build_failure_analysis.IsCorrelated('a.h', 'a_test.py')) | |
| 50 self.assertTrue(build_failure_analysis.IsCorrelated('a.h', 'a_impl_test.o')) | |
| 51 self.assertTrue(build_failure_analysis.IsCorrelated('a/b/x.cc', 'a/b/y.cc')) | |
|
qyearsley
2015/01/15 21:15:03
Maybe add a negative case -- when is IsCorrelated
stgao
2015/01/16 20:21:39
Negative case added.
If a CL changed file a.h, an
| |
| 52 | |
| 53 def testCheckFilesAgainstSuspectedCL(self): | |
| 54 failure_signal_json = { | |
| 55 'files': { | |
| 56 'src/a/b/f1.cc': [], | |
| 57 'b/c/f2.h': [10, 20], | |
| 58 'd/e/f3_test.cc': [], | |
| 59 'x/y/f4.py': [], | |
| 60 'f5_impl.cc': [] | |
| 61 } | |
| 62 } | |
| 63 change_log_json = { | |
| 64 'touched_files': [ | |
| 65 { | |
| 66 'change_type': ChangeType.ADD, | |
| 67 'old_path': '/dev/null', | |
| 68 'new_path': 'a/b/f1.cc' | |
| 69 }, | |
| 70 { | |
| 71 'change_type': ChangeType.MODIFY, | |
| 72 'old_path': 'a/b/c/f2.h', | |
| 73 'new_path': 'a/b/c/f2.h' | |
| 74 }, | |
| 75 { | |
| 76 'change_type': ChangeType.MODIFY, | |
| 77 'old_path': 'd/e/f3.h', | |
| 78 'new_path': 'd/e/f3.h' | |
| 79 }, | |
| 80 { | |
| 81 'change_type': ChangeType.DELETE, | |
| 82 'old_path': 'x/y/f4.py', | |
| 83 'new_path': '/dev/null' | |
| 84 }, | |
| 85 { | |
| 86 'change_type': ChangeType.DELETE, | |
| 87 'old_path': 'h/f5.h', | |
| 88 'new_path': '/dev/null' | |
| 89 }, | |
| 90 { | |
| 91 'change_type': ChangeType.RENAME, | |
| 92 'old_path': 't/y/x.cc', | |
| 93 'new_path': 's/z/x.cc' | |
| 94 }, | |
| 95 ] | |
| 96 } | |
| 97 | |
| 98 justification = build_failure_analysis.CheckFiles( | |
| 99 FailureSignal.FromJson(failure_signal_json), change_log_json) | |
| 100 self.assertIsNotNone(justification) | |
| 101 self.assertEqual(2, justification['suspects']) | |
| 102 self.assertEqual(13, justification['scores']) | |
| 103 | |
| 104 def testCheckFilesAgainstUnrelatedCL(self): | |
| 105 failure_signal_json = { | |
| 106 'files': { | |
| 107 'src/a/b/f.cc': [], | |
| 108 } | |
| 109 } | |
| 110 change_log_json = { | |
| 111 'touched_files': [ | |
| 112 { | |
| 113 'change_type': ChangeType.ADD, | |
| 114 'old_path': '/dev/null', | |
| 115 'new_path': 'a/d/f1.cc' | |
| 116 }, | |
| 117 ] | |
| 118 } | |
| 119 | |
| 120 justification = build_failure_analysis.CheckFiles( | |
| 121 FailureSignal.FromJson(failure_signal_json), change_log_json) | |
| 122 self.assertIsNone(justification) | |
| 123 | |
| 124 def testAnalyzeSuccesfulBuild(self): | |
| 125 failure_info = { | |
| 126 'failed': False, | |
| 127 } | |
| 128 result = build_failure_analysis.AnalyzeBuildFailure( | |
| 129 failure_info, None, None) | |
| 130 self.assertEqual(0, len(result)) | |
| 131 | |
| 132 def testAnalyzeBuildFailure(self): | |
| 133 failure_info = { | |
| 134 'failed': True, | |
| 135 'failed_steps': { | |
| 136 'a': { | |
| 137 'current_failure': 99, | |
| 138 'first_failure': 98, | |
| 139 }, | |
| 140 'b': { | |
| 141 'current_failure': 99, | |
| 142 'first_failure': 98, | |
| 143 }, | |
| 144 }, | |
| 145 'builds': { | |
| 146 '99': { | |
| 147 'blame_list': ['r99_1', 'r99_2'], | |
| 148 }, | |
| 149 '98': { | |
| 150 'blame_list': ['r98_1'], | |
| 151 }, | |
| 152 } | |
| 153 } | |
| 154 change_logs = { | |
| 155 'r99_1': { | |
| 156 'touched_files': [ | |
| 157 { | |
| 158 'change_type': ChangeType.ADD, | |
| 159 'old_path': '/dev/null', | |
| 160 'new_path': 'x/y/f99_1.cc' | |
| 161 }, | |
| 162 ], | |
| 163 }, | |
| 164 'r99_2': { | |
| 165 'touched_files': [ | |
| 166 { | |
| 167 'change_type': ChangeType.MODIFY, | |
| 168 'old_path': 'a/b/f99_2.cc', | |
| 169 'new_path': 'a/b/f99_2.cc' | |
| 170 }, | |
| 171 ], | |
| 172 }, | |
| 173 'r98_1': { | |
| 174 'touched_files': [ | |
| 175 { | |
| 176 'change_type': ChangeType.MODIFY, | |
| 177 'old_path': 'y/z/f98.cc', | |
| 178 'new_path': 'y/z/f98.cc' | |
| 179 }, | |
| 180 ], | |
| 181 }, | |
| 182 } | |
| 183 failure_signals_json = { | |
| 184 'a': { | |
| 185 'files': { | |
| 186 'src/a/b/f99_2.cc': [], | |
| 187 }, | |
| 188 }, | |
| 189 'b': { | |
| 190 'files': { | |
| 191 'f.cc': [], | |
| 192 }, | |
| 193 }, | |
| 194 } | |
| 195 expected_analysis_result = { | |
| 196 'a': { | |
| 197 'r99_2': { | |
| 198 'suspects': 0, | |
| 199 'scores': 1, | |
| 200 'hints': [ | |
| 201 'modify a/b/f99_2.cc', | |
| 202 ] | |
| 203 }, | |
| 204 }, | |
| 205 } | |
| 206 | |
| 207 analysis_result = build_failure_analysis.AnalyzeBuildFailure( | |
| 208 failure_info, change_logs, failure_signals_json) | |
| 209 self.assertEqual(expected_analysis_result, analysis_result) | |
| OLD | NEW |