| 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 testing_utils import testing | 5 from testing_utils import testing |
| 6 | 6 |
| 7 from common.git_repository import GitRepository | 7 from common.git_repository import GitRepository |
| 8 from model import wf_analysis_status | 8 from model import wf_analysis_status |
| 9 from model.wf_try_job import WfTryJob | 9 from model.wf_try_job import WfTryJob |
| 10 from waterfall.identify_try_job_culprit_pipeline import( | 10 from waterfall.identify_try_job_culprit_pipeline import( |
| 11 IdentifyTryJobCulpritPipeline) | 11 IdentifyTryJobCulpritPipeline) |
| 12 from waterfall.try_job_type import TryJobType |
| 12 | 13 |
| 13 | 14 |
| 14 class IdentifyTryJobCulpritPipelineTest(testing.AppengineTestCase): | 15 class IdentifyTryJobCulpritPipelineTest(testing.AppengineTestCase): |
| 15 | 16 |
| 16 def _MockGetChangeLog(self, revision): | 17 def _MockGetChangeLog(self, revision): |
| 17 class MockedChangeLog(object): | 18 class MockedChangeLog(object): |
| 18 | 19 |
| 19 def __init__(self, commit_position, code_review_url): | 20 def __init__(self, commit_position, code_review_url): |
| 20 self.commit_position = commit_position | 21 self.commit_position = commit_position |
| 21 self.code_review_url = code_review_url | 22 self.code_review_url = code_review_url |
| 22 | 23 |
| 23 mock_change_logs = {} | 24 mock_change_logs = {} |
| 25 mock_change_logs['rev1'] = MockedChangeLog('1', 'url_1') |
| 24 mock_change_logs['rev2'] = MockedChangeLog('2', 'url_2') | 26 mock_change_logs['rev2'] = MockedChangeLog('2', 'url_2') |
| 25 return mock_change_logs.get(revision) | 27 return mock_change_logs.get(revision) |
| 26 | 28 |
| 27 def testGetFailedRevisionFromResultsDict(self): | 29 def testGetFailedRevisionFromResultsDict(self): |
| 28 self.assertIsNone( | 30 self.assertIsNone( |
| 29 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict({})) | 31 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict({})) |
| 30 self.assertEqual( | 32 self.assertEqual( |
| 31 None, | 33 None, |
| 32 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict( | 34 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromResultsDict( |
| 33 {'rev1': 'passed'})) | 35 {'rev1': 'passed'})) |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 self.assertEqual( | 72 self.assertEqual( |
| 71 'rev2', | 73 'rev2', |
| 72 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromCompileResult( | 74 IdentifyTryJobCulpritPipeline._GetFailedRevisionFromCompileResult( |
| 73 { | 75 { |
| 74 'report': [ | 76 'report': [ |
| 75 ['rev1', 'passed'], | 77 ['rev1', 'passed'], |
| 76 ['rev2', 'failed'] | 78 ['rev2', 'failed'] |
| 77 ] | 79 ] |
| 78 })) | 80 })) |
| 79 | 81 |
| 80 def testGetCulpritFromFailedRevision(self): | |
| 81 self.mock(GitRepository, 'GetChangeLog', self._MockGetChangeLog) | |
| 82 self.assertIsNone( | |
| 83 IdentifyTryJobCulpritPipeline._GetCulpritFromFailedRevision(None)) | |
| 84 self.assertIsNone( | |
| 85 IdentifyTryJobCulpritPipeline._GetCulpritFromFailedRevision( | |
| 86 'revision_with_no_change_log')) | |
| 87 self.assertEqual( | |
| 88 { | |
| 89 'revision': 'rev2', | |
| 90 'commit_position': '2', | |
| 91 'review_url': 'url_2' | |
| 92 }, | |
| 93 IdentifyTryJobCulpritPipeline._GetCulpritFromFailedRevision('rev2')) | |
| 94 | |
| 95 def testIdentifyCulpritForCompileTryJobNoCulprit(self): | 82 def testIdentifyCulpritForCompileTryJobNoCulprit(self): |
| 96 master_name = 'm' | 83 master_name = 'm' |
| 97 builder_name = 'b' | 84 builder_name = 'b' |
| 98 build_number = 1 | 85 build_number = 1 |
| 99 try_job_id = '1' | |
| 100 | 86 |
| 101 try_job = WfTryJob.Create(master_name, builder_name, build_number) | 87 try_job = WfTryJob.Create(master_name, builder_name, build_number) |
| 102 try_job.put() | 88 try_job.put() |
| 103 | 89 |
| 104 pipeline = IdentifyTryJobCulpritPipeline() | 90 pipeline = IdentifyTryJobCulpritPipeline() |
| 105 culprit = pipeline.run( | 91 culprit = pipeline.run( |
| 106 master_name, builder_name, build_number, try_job_id, None) | 92 master_name, builder_name, build_number, ['rev1'], |
| 93 TryJobType.COMPILE, '1', None) |
| 94 try_job = WfTryJob.Get(master_name, builder_name, build_number) |
| 107 | 95 |
| 108 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) | 96 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) |
| 109 self.assertEqual([], try_job.compile_results) | 97 self.assertEqual([], try_job.compile_results) |
| 110 self.assertIsNone(culprit) | 98 self.assertIsNone(culprit) |
| 111 | 99 |
| 112 def testIdentifyCulpritForCompileTryJobSuccess(self): | 100 def testIdentifyCulpritForCompileTryJobSuccess(self): |
| 113 master_name = 'm' | 101 master_name = 'm' |
| 114 builder_name = 'b' | 102 builder_name = 'b' |
| 115 build_number = 1 | 103 build_number = 1 |
| 116 try_job_id = '1' | |
| 117 compile_result = { | 104 compile_result = { |
| 118 'report': { | 105 'report': { |
| 119 'result': { | 106 'result': { |
| 120 'rev1': 'passed', | 107 'rev1': 'passed', |
| 121 'rev2': 'failed' | 108 'rev2': 'failed' |
| 122 } | 109 } |
| 123 }, | 110 }, |
| 124 } | 111 } |
| 125 | 112 |
| 126 try_job = WfTryJob.Create(master_name, builder_name, build_number) | 113 try_job = WfTryJob.Create(master_name, builder_name, build_number) |
| 127 try_job.status = wf_analysis_status.ANALYZING | 114 try_job.status = wf_analysis_status.ANALYZING |
| 128 try_job.compile_results = [{ | 115 try_job.compile_results = [{ |
| 129 'report': { | 116 'report': { |
| 130 'result': { | 117 'result': { |
| 131 'rev1': 'passed', | 118 'rev1': 'passed', |
| 132 'rev2': 'failed' | 119 'rev2': 'failed' |
| 133 }, | 120 }, |
| 134 }, | 121 }, |
| 135 'try_job_id': '1', | 122 'try_job_id': '1', |
| 136 }] | 123 }] |
| 137 try_job.put() | 124 try_job.put() |
| 138 | 125 |
| 139 self.mock(GitRepository, 'GetChangeLog', self._MockGetChangeLog) | 126 self.mock(GitRepository, 'GetChangeLog', self._MockGetChangeLog) |
| 140 | 127 |
| 141 pipeline = IdentifyTryJobCulpritPipeline() | 128 pipeline = IdentifyTryJobCulpritPipeline() |
| 142 culprit = pipeline.run( | 129 culprit = pipeline.run( |
| 143 master_name, builder_name, build_number, try_job_id, compile_result) | 130 master_name, builder_name, build_number, ['rev1'], |
| 144 | 131 TryJobType.COMPILE, '1', compile_result) |
| 145 expected_compile_result = { | 132 expected_compile_result = { |
| 146 'report': { | 133 'report': { |
| 147 'result': { | 134 'result': { |
| 148 'rev1': 'passed', | 135 'rev1': 'passed', |
| 149 'rev2': 'failed' | 136 'rev2': 'failed' |
| 150 } | 137 } |
| 151 }, | 138 }, |
| 152 'try_job_id': '1', | 139 'try_job_id': '1', |
| 153 'culprit': { | 140 'culprit': { |
| 154 'revision': 'rev2', | 141 'revision': 'rev2', |
| 155 'commit_position': '2', | 142 'commit_position': '2', |
| 156 'review_url': 'url_2' | 143 'review_url': 'url_2' |
| 157 } | 144 } |
| 158 } | 145 } |
| 159 | 146 |
| 160 self.assertEqual(expected_compile_result['culprit'], culprit) | 147 self.assertEqual(expected_compile_result['culprit'], culprit) |
| 161 | 148 |
| 162 try_job = WfTryJob.Get(master_name, builder_name, build_number) | 149 try_job = WfTryJob.Get(master_name, builder_name, build_number) |
| 150 |
| 163 self.assertEqual(expected_compile_result, try_job.compile_results[-1]) | 151 self.assertEqual(expected_compile_result, try_job.compile_results[-1]) |
| 164 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) | 152 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) |
| 165 | 153 |
| 154 def testIdentifyCulpritForCompileReturnNoneIfAllPassed(self): |
| 155 master_name = 'm' |
| 156 builder_name = 'b' |
| 157 build_number = 1 |
| 158 compile_result = { |
| 159 'report': { |
| 160 'result': { |
| 161 'rev1': 'passed', |
| 162 'rev2': 'passed' |
| 163 } |
| 164 }, |
| 165 'url': 'url', |
| 166 'try_job_id': '1', |
| 167 } |
| 168 WfTryJob.Create(master_name, builder_name, build_number).put() |
| 169 |
| 170 pipeline = IdentifyTryJobCulpritPipeline() |
| 171 culprit = pipeline.run( |
| 172 master_name, builder_name, build_number, ['rev1'], |
| 173 TryJobType.COMPILE, '1', compile_result) |
| 174 try_job = WfTryJob.Get(master_name, builder_name, build_number) |
| 175 |
| 176 self.assertIsNone(culprit) |
| 177 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) |
| 178 |
| 166 # TODO(lijeffrey): Deprecate all tests with compile_results whose 'result' | 179 # TODO(lijeffrey): Deprecate all tests with compile_results whose 'result' |
| 167 # key is a list once it is returned as a dict from the recipe. | 180 # key is a list once it is returned as a dict from the recipe. |
| 168 def testIdentifyCulpritForCompileListTryJobSuccess(self): | 181 def testIdentifyCulpritForCompileListTryJobSuccess(self): |
| 169 master_name = 'm' | 182 master_name = 'm' |
| 170 builder_name = 'b' | 183 builder_name = 'b' |
| 171 build_number = 1 | 184 build_number = 1 |
| 172 try_job_id = '1' | |
| 173 compile_result = { | 185 compile_result = { |
| 174 'report': [ | 186 'report': { |
| 175 ['rev1', 'passed'], | 187 'result': { |
| 176 ['rev2', 'failed'] | 188 'rev1': 'passed', |
| 177 ], | 189 'rev2': 'failed' |
| 190 } |
| 191 }, |
| 178 'url': 'url', | 192 'url': 'url', |
| 179 'try_job_id': '1', | 193 'try_job_id': '1', |
| 180 } | 194 } |
| 181 | 195 |
| 182 try_job = WfTryJob.Create(master_name, builder_name, build_number) | 196 try_job = WfTryJob.Create(master_name, builder_name, build_number) |
| 183 try_job.status = wf_analysis_status.ANALYZING | 197 try_job.status = wf_analysis_status.ANALYZING |
| 184 try_job.compile_results = [{ | 198 try_job.compile_results = [compile_result] |
| 185 'report': [ | |
| 186 ['rev1', 'passed'], | |
| 187 ['rev2', 'failed'] | |
| 188 ], | |
| 189 'url': 'url', | |
| 190 'try_job_id': '1', | |
| 191 }] | |
| 192 try_job.put() | 199 try_job.put() |
| 193 | 200 |
| 194 self.mock(GitRepository, 'GetChangeLog', self._MockGetChangeLog) | 201 self.mock(GitRepository, 'GetChangeLog', self._MockGetChangeLog) |
| 195 | 202 |
| 196 pipeline = IdentifyTryJobCulpritPipeline() | 203 pipeline = IdentifyTryJobCulpritPipeline() |
| 197 culprit = pipeline.run( | 204 culprit = pipeline.run( |
| 198 master_name, builder_name, build_number, try_job_id, compile_result) | 205 master_name, builder_name, build_number, ['rev1'], |
| 206 TryJobType.COMPILE, '1', compile_result) |
| 199 | 207 |
| 200 expected_compile_result = { | 208 expected_compile_result = { |
| 201 'report': [ | 209 'report': { |
| 202 ['rev1', 'passed'], | 210 'result': { |
| 203 ['rev2', 'failed'] | 211 'rev1': 'passed', |
| 204 ], | 212 'rev2': 'failed' |
| 213 } |
| 214 }, |
| 205 'url': 'url', | 215 'url': 'url', |
| 206 'try_job_id': '1', | 216 'try_job_id': '1', |
| 207 'culprit': { | 217 'culprit': { |
| 208 'revision': 'rev2', | 218 'revision': 'rev2', |
| 209 'commit_position': '2', | 219 'commit_position': '2', |
| 210 'review_url': 'url_2' | 220 'review_url': 'url_2' |
| 211 } | 221 } |
| 212 } | 222 } |
| 213 | 223 |
| 214 self.assertEqual(expected_compile_result['culprit'], culprit) | 224 self.assertEqual(expected_compile_result['culprit'], culprit) |
| 215 | 225 |
| 216 try_job = WfTryJob.Get(master_name, builder_name, build_number) | 226 try_job = WfTryJob.Get(master_name, builder_name, build_number) |
| 217 self.assertEqual(expected_compile_result, try_job.compile_results[-1]) | 227 self.assertEqual(expected_compile_result, try_job.compile_results[-1]) |
| 218 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) | 228 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) |
| 229 |
| 230 def testIdentifyCulpritForTestTryJobReturnNoneIfNoTryJobResult(self): |
| 231 master_name = 'm' |
| 232 builder_name = 'b' |
| 233 build_number = 1 |
| 234 |
| 235 try_job = WfTryJob.Create(master_name, builder_name, build_number) |
| 236 try_job.status = wf_analysis_status.ANALYZING |
| 237 try_job.put() |
| 238 |
| 239 pipeline = IdentifyTryJobCulpritPipeline() |
| 240 culprit = pipeline.run( |
| 241 master_name, builder_name, build_number, ['rev1', 'rev2'], |
| 242 TryJobType.TEST, '1', None) |
| 243 |
| 244 self.assertIsNone(culprit) |
| 245 |
| 246 def testIdentifyCulpritForTestTryJobReturnNoneIfNoRevisionToCheck(self): |
| 247 master_name = 'm' |
| 248 builder_name = 'b' |
| 249 build_number = 1 |
| 250 test_result = { |
| 251 'report': { |
| 252 'rev1': { |
| 253 'a_test': { |
| 254 'status': 'failed', |
| 255 'valid': True, |
| 256 'failures': ['a_test1'] |
| 257 } |
| 258 } |
| 259 }, |
| 260 'url': 'url', |
| 261 'try_job_id': '1' |
| 262 } |
| 263 |
| 264 try_job = WfTryJob.Create(master_name, builder_name, build_number) |
| 265 try_job.status = wf_analysis_status.ANALYZING |
| 266 try_job.put() |
| 267 |
| 268 pipeline = IdentifyTryJobCulpritPipeline() |
| 269 culprit = pipeline.run( |
| 270 master_name, builder_name, build_number, [], TryJobType.TEST, '1', |
| 271 test_result) |
| 272 |
| 273 self.assertIsNone(culprit) |
| 274 |
| 275 def testIdentifyCulpritForTestTryJobReturnNoneIfNoCulpritInfo(self): |
| 276 master_name = 'm' |
| 277 builder_name = 'b' |
| 278 build_number = 1 |
| 279 test_result = { |
| 280 'report': { |
| 281 'rev3': { |
| 282 'a_test': { |
| 283 'status': 'failed', |
| 284 'valid': True, |
| 285 'failures': ['a_test1'] |
| 286 } |
| 287 } |
| 288 }, |
| 289 'url': 'url', |
| 290 'try_job_id': '1' |
| 291 } |
| 292 |
| 293 try_job = WfTryJob.Create(master_name, builder_name, build_number) |
| 294 try_job.status = wf_analysis_status.ANALYZING |
| 295 try_job.put() |
| 296 |
| 297 pipeline = IdentifyTryJobCulpritPipeline() |
| 298 culprit = pipeline.run( |
| 299 master_name, builder_name, build_number, ['rev3'], TryJobType.TEST, |
| 300 '1', test_result) |
| 301 |
| 302 expected_culprit = { |
| 303 'a_test': { |
| 304 'tests':{ |
| 305 'a_test1': { |
| 306 'revision': 'rev3' |
| 307 } |
| 308 } |
| 309 } |
| 310 } |
| 311 self.assertEqual(expected_culprit, culprit) |
| 312 |
| 313 def testIdentifyCulpritForTestTryJobSuccess(self): |
| 314 master_name = 'm' |
| 315 builder_name = 'b' |
| 316 build_number = 1 |
| 317 test_result = { |
| 318 'report': { |
| 319 'rev1': { |
| 320 'a_test': { |
| 321 'status': 'failed', |
| 322 'valid': True, |
| 323 'failures': ['a_test1'] |
| 324 }, |
| 325 'b_test': { |
| 326 'status': 'failed', |
| 327 'valid': True, |
| 328 'failures': ['b_test1'] |
| 329 }, |
| 330 'c_test': { |
| 331 'status': 'passed', |
| 332 'valid': True |
| 333 } |
| 334 }, |
| 335 'rev2': { |
| 336 'a_test': { |
| 337 'status': 'failed', |
| 338 'valid': True, |
| 339 'failures': ['a_test1', 'a_test2'] |
| 340 }, |
| 341 'b_test': { |
| 342 'status': 'passed', |
| 343 'valid': True |
| 344 }, |
| 345 'c_test': { |
| 346 'status': 'failed', |
| 347 'valid': True, |
| 348 'failures': [] |
| 349 } |
| 350 } |
| 351 }, |
| 352 'url': 'url', |
| 353 'try_job_id': '1' |
| 354 } |
| 355 |
| 356 try_job = WfTryJob.Create(master_name, builder_name, build_number) |
| 357 try_job.status = wf_analysis_status.ANALYZING |
| 358 try_job.test_results = [test_result] |
| 359 try_job.put() |
| 360 |
| 361 self.mock(GitRepository, 'GetChangeLog', self._MockGetChangeLog) |
| 362 |
| 363 pipeline = IdentifyTryJobCulpritPipeline() |
| 364 culprit = pipeline.run( |
| 365 master_name, builder_name, build_number, ['rev1', 'rev2'], |
| 366 TryJobType.TEST, '1', test_result) |
| 367 |
| 368 expected_test_result = { |
| 369 'report': { |
| 370 'rev1': { |
| 371 'a_test': { |
| 372 'status': 'failed', |
| 373 'valid': True, |
| 374 'failures': ['a_test1'] |
| 375 }, |
| 376 'b_test': { |
| 377 'status': 'failed', |
| 378 'valid': True, |
| 379 'failures': ['b_test1'] |
| 380 }, |
| 381 'c_test': { |
| 382 'status': 'passed', |
| 383 'valid': True |
| 384 } |
| 385 }, |
| 386 'rev2': { |
| 387 'a_test': { |
| 388 'status': 'failed', |
| 389 'valid': True, |
| 390 'failures': ['a_test1', 'a_test2'] |
| 391 }, |
| 392 'b_test': { |
| 393 'status': 'passed', |
| 394 'valid': True |
| 395 }, |
| 396 'c_test': { |
| 397 'status': 'failed', |
| 398 'valid': True, |
| 399 'failures': [] |
| 400 } |
| 401 } |
| 402 }, |
| 403 'url': 'url', |
| 404 'try_job_id': '1', |
| 405 'culprit': { |
| 406 'a_test': { |
| 407 'tests': { |
| 408 'a_test1': { |
| 409 'revision': 'rev1', |
| 410 'commit_position': '1', |
| 411 'review_url': 'url_1' |
| 412 }, |
| 413 'a_test2': { |
| 414 'revision': 'rev2', |
| 415 'commit_position': '2', |
| 416 'review_url': 'url_2' |
| 417 } |
| 418 } |
| 419 }, |
| 420 'b_test': { |
| 421 'tests': { |
| 422 'b_test1': { |
| 423 'revision': 'rev1', |
| 424 'commit_position': '1', |
| 425 'review_url': 'url_1' |
| 426 } |
| 427 } |
| 428 }, |
| 429 'c_test': { |
| 430 'revision': 'rev2', |
| 431 'commit_position': '2', |
| 432 'review_url': 'url_2', |
| 433 'tests': {} |
| 434 } |
| 435 } |
| 436 } |
| 437 |
| 438 self.assertEqual(expected_test_result['culprit'], culprit) |
| 439 |
| 440 try_job = WfTryJob.Get(master_name, builder_name, build_number) |
| 441 self.assertEqual(expected_test_result, try_job.test_results[-1]) |
| 442 self.assertEqual(wf_analysis_status.ANALYZED, try_job.status) |
| OLD | NEW |