Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 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 import copy | 4 import copy |
| 5 import json | 5 import json |
| 6 | 6 |
| 7 from google.appengine.api import app_identity | 7 from google.appengine.api import app_identity |
| 8 | 8 |
| 9 from common.pipeline_wrapper import pipeline_handlers | 9 from common.pipeline_wrapper import pipeline_handlers |
| 10 from crash import crash_pipeline | 10 from crash import crash_pipeline |
| 11 from crash import findit_for_chromecrash | 11 from crash import findit_for_chromecrash |
| 12 from crash.crash_report import CrashReport | |
| 13 from crash.findit_for_chromecrash import FinditForFracas | |
| 14 from crash.stacktrace import Stacktrace | |
| 12 from crash.test.crash_testcase import CrashTestCase | 15 from crash.test.crash_testcase import CrashTestCase |
| 16 from crash.type_enums import CrashClient | |
| 13 from model import analysis_status | 17 from model import analysis_status |
| 14 from model.crash.fracas_crash_analysis import FracasCrashAnalysis | 18 from model.crash.fracas_crash_analysis import FracasCrashAnalysis |
| 15 | 19 |
| 16 | 20 |
| 21 # TODO(wrengr): Our use of this highly suggests that |crash_identifiers| | |
| 22 # don't actually need to be passed around everywhere. The only parts that | |
| 23 # matter are the |channel| and the |process_type|, which can be passed | |
| 24 # separately. | |
| 25 def CrashIdentifiers(report): | |
| 26 return { | |
| 27 'chrome_version': report.crashed_version, | |
| 28 'signature': report.signature, | |
| 29 'channel': 'canary', | |
| 30 'platform': report.platform, | |
| 31 'process_type': 'browser' | |
| 32 } | |
| 33 | |
| 34 DUMMY_REPORT1 = CrashReport( | |
| 35 crashed_version = '1', | |
| 36 signature = 'signature', | |
| 37 platform = 'win', | |
| 38 stacktrace = Stacktrace(), | |
| 39 regression_range = None) | |
| 40 | |
| 41 DUMMY_CRASH_IDENTIFIERS1 = CrashIdentifiers(DUMMY_REPORT1) | |
| 42 | |
| 17 class CrashPipelineTest(CrashTestCase): | 43 class CrashPipelineTest(CrashTestCase): |
| 18 app_module = pipeline_handlers._APP | 44 app_module = pipeline_handlers._APP |
| 19 | 45 |
| 20 def testNoAnalysisIfLastOneIsNotFailed(self): | 46 def testNoAnalysisIfLastOneIsNotFailed(self): |
| 21 chrome_version = '1' | |
| 22 signature = 'signature' | |
| 23 platform = 'win' | |
| 24 crash_identifiers = { | |
| 25 'chrome_version': chrome_version, | |
| 26 'signature': signature, | |
| 27 'channel': 'canary', | |
| 28 'platform': platform, | |
| 29 'process_type': 'browser', | |
| 30 } | |
| 31 for status in (analysis_status.PENDING, analysis_status.RUNNING, | 47 for status in (analysis_status.PENDING, analysis_status.RUNNING, |
| 32 analysis_status.COMPLETED, analysis_status.SKIPPED): | 48 analysis_status.COMPLETED, analysis_status.SKIPPED): |
| 33 analysis = FracasCrashAnalysis.Create(crash_identifiers) | 49 analysis = FracasCrashAnalysis.Create(DUMMY_CRASH_IDENTIFIERS1) |
| 34 analysis.status = status | 50 analysis.status = status |
| 35 analysis.put() | 51 analysis.put() |
| 36 self.assertFalse(crash_pipeline._NeedsNewAnalysis( | 52 self.assertFalse(crash_pipeline._NeedsNewAnalysis( |
| 37 crash_identifiers, chrome_version, signature, 'fracas', | 53 FinditForFracas(), DUMMY_CRASH_IDENTIFIERS1, DUMMY_REPORT1)) |
| 38 platform, None, {'channel': 'canary'})) | |
| 39 | 54 |
| 40 def testAnalysisNeededIfLastOneFailed(self): | 55 def testAnalysisNeededIfLastOneFailed(self): |
| 41 chrome_version = '1' | 56 analysis = FracasCrashAnalysis.Create(DUMMY_CRASH_IDENTIFIERS1) |
| 42 signature = 'signature' | |
| 43 platform = 'win' | |
| 44 crash_identifiers = { | |
| 45 'chrome_version': chrome_version, | |
| 46 'signature': signature, | |
| 47 'channel': 'canary', | |
| 48 'platform': platform, | |
| 49 'process_type': 'browser', | |
| 50 } | |
| 51 analysis = FracasCrashAnalysis.Create(crash_identifiers) | |
| 52 analysis.status = analysis_status.ERROR | 57 analysis.status = analysis_status.ERROR |
| 53 analysis.put() | 58 analysis.put() |
| 54 self.assertTrue(crash_pipeline._NeedsNewAnalysis( | 59 self.assertTrue(crash_pipeline._NeedsNewAnalysis( |
| 55 crash_identifiers, chrome_version, signature, 'fracas', | 60 FinditForFracas(), DUMMY_CRASH_IDENTIFIERS1, DUMMY_REPORT1)) |
| 56 platform, None, {'channel': 'canary'})) | |
| 57 | 61 |
| 58 def testAnalysisNeededIfNoAnalysisYet(self): | 62 def testAnalysisNeededIfNoAnalysisYet(self): |
| 59 chrome_version = '1' | |
| 60 signature = 'signature' | |
| 61 platform = 'win' | |
| 62 crash_identifiers = { | |
| 63 'chrome_version': chrome_version, | |
| 64 'signature': signature, | |
| 65 'channel': 'canary', | |
| 66 'platform': platform, | |
| 67 'process_type': 'browser', | |
| 68 } | |
| 69 self.assertTrue(crash_pipeline._NeedsNewAnalysis( | 63 self.assertTrue(crash_pipeline._NeedsNewAnalysis( |
| 70 crash_identifiers, chrome_version, signature, 'fracas', | 64 FinditForFracas(), DUMMY_CRASH_IDENTIFIERS1, DUMMY_REPORT1)) |
| 71 platform, None, {'channel': 'canary'})) | |
| 72 | 65 |
| 73 def testUnsupportedChannelOrPlatformSkipped(self): | 66 def testUnsupportedChannelOrPlatformSkipped(self): |
| 67 channel = None | |
| 74 self.assertFalse( | 68 self.assertFalse( |
| 75 crash_pipeline.ScheduleNewAnalysisForCrash( | 69 crash_pipeline.ScheduleNewAnalysisForCrash(FinditForFracas(), {}, |
| 76 {}, None, None, 'fracas', 'win', | 70 CrashReport(None, None, 'win', Stacktrace(), None), channel)) |
| 77 None, {'channel': 'unsupported_channel', | |
| 78 'historical_metadata': None})) | |
| 79 self.assertFalse( | 71 self.assertFalse( |
| 80 crash_pipeline.ScheduleNewAnalysisForCrash( | 72 crash_pipeline.ScheduleNewAnalysisForCrash(FinditForFracas(), {}, |
| 81 {}, None, None, 'fracas', 'unsupported_platform', | 73 CrashReport(None, None, 'unsupported_platform', Stacktrace(), None), |
| 82 None, {'channel': 'unsupported_channel', | 74 channel)) |
| 83 'historical_metadata': None})) | |
| 84 | 75 |
| 85 def testBlackListSignatureSipped(self): | 76 def testBlackListSignatureSipped(self): |
| 77 channel = None | |
| 78 signature = 'Blacklist marker signature' | |
| 86 self.assertFalse( | 79 self.assertFalse( |
| 87 crash_pipeline.ScheduleNewAnalysisForCrash( | 80 crash_pipeline.ScheduleNewAnalysisForCrash(FinditForFracas(), {}, |
| 88 {}, None, 'Blacklist marker signature', 'fracas', 'win', | 81 CrashReport(None, signature, 'win', Stacktrace(), None), channel)) |
| 89 None, {'channel': 'canary', | |
| 90 'historical_metadata': None})) | |
| 91 | 82 |
| 92 def testPlatformRename(self): | 83 def testPlatformRename(self): |
| 93 def _MockNeedsNewAnalysis(*args): | 84 channel = 'canary' |
| 94 self.assertEqual(args, | 85 def _MockNeedsNewAnalysis(findit_client, crash_identifiers, report): |
| 95 ({}, None, 'signature', 'fracas', 'unix', None, | 86 |
| 96 {'channel': 'canary'})) | 87 self.assertEqual( |
| 88 (findit_client.client_id, crash_identifiers, report), | |
| 89 (CrashClient.FRACAS, {}, | |
| 90 CrashReport(None, 'signature', 'unix', Stacktrace(), None))) | |
| 97 return False | 91 return False |
| 98 | 92 |
| 99 self.mock(crash_pipeline, '_NeedsNewAnalysis', _MockNeedsNewAnalysis) | 93 self.mock(crash_pipeline, '_NeedsNewAnalysis', _MockNeedsNewAnalysis) |
| 100 | 94 |
| 101 crash_pipeline.ScheduleNewAnalysisForCrash( | 95 crash_pipeline.ScheduleNewAnalysisForCrash(FinditForFracas(), {}, |
| 102 {}, None, 'signature', 'fracas', 'linux', | 96 CrashReport(None, 'signature', 'linux', Stacktrace(), None), channel) |
| 103 None, {'channel': 'canary'}) | |
| 104 | 97 |
| 105 def testNoAnalysisNeeded(self): | 98 def testNoAnalysisNeeded(self): |
| 106 chrome_version = '1' | 99 analysis = FracasCrashAnalysis.Create(DUMMY_CRASH_IDENTIFIERS1) |
| 107 signature = 'signature' | |
| 108 platform = 'win' | |
| 109 channel = 'canary' | |
| 110 crash_identifiers = { | |
| 111 'chrome_version': chrome_version, | |
| 112 'signature': signature, | |
| 113 'channel': channel, | |
| 114 'platform': platform, | |
| 115 'process_type': 'browser', | |
| 116 } | |
| 117 analysis = FracasCrashAnalysis.Create(crash_identifiers) | |
| 118 analysis.status = analysis_status.COMPLETED | 100 analysis.status = analysis_status.COMPLETED |
| 119 analysis.put() | 101 analysis.put() |
| 120 | |
| 121 self.assertFalse( | 102 self.assertFalse( |
| 122 crash_pipeline.ScheduleNewAnalysisForCrash( | 103 crash_pipeline.ScheduleNewAnalysisForCrash( |
| 123 crash_identifiers, chrome_version, signature, 'fracas', | 104 FinditForFracas(), DUMMY_CRASH_IDENTIFIERS1, DUMMY_REPORT1, |
| 124 platform, None, {'channel': channel, | 105 analysis.channel)) |
| 125 'historical_metadata': None})) | |
| 126 | 106 |
| 127 def _TestRunningAnalysisForResult(self, analysis_result, analysis_tags): | 107 def _TestRunningAnalysisForResult(self, analysis_result, analysis_tags): |
| 128 pubsub_publish_requests = [] | 108 pubsub_publish_requests = [] |
| 129 def Mocked_PublishMessagesToTopic(messages_data, topic): | 109 def Mocked_PublishMessagesToTopic(messages_data, topic): |
| 130 pubsub_publish_requests.append((messages_data, topic)) | 110 pubsub_publish_requests.append((messages_data, topic)) |
| 131 self.mock(crash_pipeline.pubsub_util, 'PublishMessagesToTopic', | 111 self.mock(crash_pipeline.pubsub_util, 'PublishMessagesToTopic', |
| 132 Mocked_PublishMessagesToTopic) | 112 Mocked_PublishMessagesToTopic) |
| 133 | 113 |
| 134 analyzed_crashes = [] | 114 analyzed_crashes = [] |
| 135 class Mocked_FinditForChromeCrash(object): | 115 class _MockFinditForFracas(FinditForFracas): |
| 136 def __init__(self, *_): | |
| 137 pass | |
| 138 def FindCulprit(self, *args): | 116 def FindCulprit(self, *args): |
| 139 analyzed_crashes.append(args) | 117 analyzed_crashes.append(args) |
| 118 # TODO(wrengr): this needs to return a Culprit object | |
| 140 return analysis_result, analysis_tags | 119 return analysis_result, analysis_tags |
| 141 self.mock(findit_for_chromecrash, 'FinditForChromeCrash', | |
| 142 Mocked_FinditForChromeCrash) | |
| 143 | 120 |
| 144 chrome_version = '1' | |
| 145 signature = 'signature' | |
| 146 platform = 'win' | |
| 147 channel = 'canary' | |
| 148 crash_identifiers = { | |
| 149 'chrome_version': chrome_version, | |
| 150 'signature': signature, | |
| 151 'channel': channel, | |
| 152 'platform': platform, | |
| 153 'process_type': 'browser', | |
| 154 } | |
| 155 stack_trace = 'frame1\nframe2\nframe3' | 121 stack_trace = 'frame1\nframe2\nframe3' |
| 156 chrome_version = '50.2500.0.1' | 122 chrome_version = '50.2500.0.1' |
| 157 historical_metadata = None | 123 historical_metadata = None |
| 158 | 124 |
| 159 mock_host = 'https://host.com' | 125 mock_host = 'https://host.com' |
| 160 self.mock(app_identity, 'get_default_version_hostname', lambda: mock_host) | 126 self.mock(app_identity, 'get_default_version_hostname', lambda: mock_host) |
| 161 | 127 |
| 128 channel = 'canary' | |
| 162 self.assertTrue( | 129 self.assertTrue( |
| 163 crash_pipeline.ScheduleNewAnalysisForCrash( | 130 crash_pipeline.ScheduleNewAnalysisForCrash( |
| 164 crash_identifiers, chrome_version, signature, 'fracas', | 131 _MockFinditForFracas(), |
| 165 platform, stack_trace, | 132 DUMMY_CRASH_IDENTIFIERS1, |
| 166 {'channel': channel, 'historical_metadata': historical_metadata})) | 133 DUMMY_REPORT1._replace(stacktrace=stack_trace), channel)) |
| 167 | 134 |
| 135 # TODO(katesonia): this method call is crashing with an AppError | |
| 136 # 500. How to fix it? | |
| 168 self.execute_queued_tasks() | 137 self.execute_queued_tasks() |
| 169 | 138 |
| 170 self.assertEqual(1, len(pubsub_publish_requests)) | 139 self.assertEqual(1, len(pubsub_publish_requests)) |
| 171 | 140 |
| 172 processed_analysis_result = copy.deepcopy(analysis_result) | 141 processed_analysis_result = copy.deepcopy(analysis_result) |
| 173 processed_analysis_result['feedback_url'] = ( | 142 processed_analysis_result['feedback_url'] = ( |
| 174 mock_host + '/crash/fracas-result-feedback?' | 143 mock_host + '/crash/fracas-result-feedback?' |
| 175 'key=agx0ZXN0YmVkLXRlc3RyQQsSE0ZyYWNhc0NyYXNoQW5hbHlzaXMiKGU2ZWIyNj' | 144 'key=agx0ZXN0YmVkLXRlc3RyQQsSE0ZyYWNhc0NyYXNoQW5hbHlzaXMiKGU2ZWIyNj' |
| 176 'A2OTBlYTAyMjVjNWNjYTM3ZTNjYTlmYWExOGVmYjVlM2UM') | 145 'A2OTBlYTAyMjVjNWNjYTM3ZTNjYTlmYWExOGVmYjVlM2UM') |
| 177 | 146 |
| 178 if 'suspected_cls' in processed_analysis_result: | 147 if 'suspected_cls' in processed_analysis_result: |
| 179 for cl in processed_analysis_result['suspected_cls']: | 148 for cl in processed_analysis_result['suspected_cls']: |
| 180 cl['confidence'] = round(cl['confidence'], 2) | 149 cl['confidence'] = round(cl['confidence'], 2) |
| 181 cl.pop('reason', None) | 150 cl.pop('reason', None) |
| 182 | 151 |
| 183 expected_messages_data = [json.dumps({ | 152 expected_messages_data = [json.dumps({ |
| 184 'crash_identifiers': crash_identifiers, | 153 'crash_identifiers': DUMMY_CRASH_IDENTIFIERS1, |
| 185 'client_id': 'fracas', | 154 'client_id': 'fracas', |
| 186 'result': processed_analysis_result, | 155 'result': processed_analysis_result, |
| 187 }, sort_keys=True)] | 156 }, sort_keys=True)] |
| 188 self.assertEqual(expected_messages_data, pubsub_publish_requests[0][0]) | 157 self.assertEqual(expected_messages_data, pubsub_publish_requests[0][0]) |
| 189 | 158 |
| 190 self.assertEqual(1, len(analyzed_crashes)) | 159 self.assertEqual(1, len(analyzed_crashes)) |
| 191 self.assertEqual( | 160 self.assertEqual( |
| 192 (signature, platform, stack_trace, chrome_version, None), | 161 (DUMMY_REPORT1.signature, DUMMY_REPORT1.platform, stack_trace, chrome_ve rsion, None), |
| 193 analyzed_crashes[0]) | 162 analyzed_crashes[0]) |
| 194 | 163 |
| 195 analysis = FracasCrashAnalysis.Get(crash_identifiers) | 164 analysis = FracasCrashAnalysis.Get(DUMMY_CRASH_IDENTIFIERS1) |
| 196 self.assertEqual(analysis_result, analysis.result) | 165 self.assertEqual(analysis_result, analysis.result) |
| 197 return analysis | 166 return analysis |
| 198 | 167 |
| 199 | 168 |
| 200 def testRunningAnalysis(self): | 169 def testRunningAnalysis(self): |
|
stgao
2016/10/12 15:46:58
Hopefully https://codereview.chromium.org/24145230
wrengr
2016/10/12 21:14:51
Um, that's this CL. Did you have another one in mi
stgao
2016/10/13 06:03:17
Sorry, I don't understand this. Would you mind ela
wrengr
2016/10/18 23:13:54
My/this CL is 2414523002, so when I follow the lin
| |
| 201 analysis_result = { | 170 analysis_result = { |
| 202 'found': True, | 171 'found': True, |
| 203 'suspected_cls': [], | 172 'suspected_cls': [], |
| 204 'other_data': 'data', | 173 'other_data': 'data', |
| 205 } | 174 } |
| 206 analysis_tags = { | 175 analysis_tags = { |
| 207 'found_suspects': True, | 176 'found_suspects': True, |
| 208 'has_regression_range': True, | 177 'has_regression_range': True, |
| 209 'solution': 'core', | 178 'solution': 'core', |
| 210 'unsupported_tag': '', | 179 'unsupported_tag': '', |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 250 'unsupported_tag': '', | 219 'unsupported_tag': '', |
| 251 } | 220 } |
| 252 | 221 |
| 253 analysis = self._TestRunningAnalysisForResult( | 222 analysis = self._TestRunningAnalysisForResult( |
| 254 analysis_result, analysis_tags) | 223 analysis_result, analysis_tags) |
| 255 self.assertTrue(analysis.has_regression_range) | 224 self.assertTrue(analysis.has_regression_range) |
| 256 self.assertTrue(analysis.found_suspects) | 225 self.assertTrue(analysis.found_suspects) |
| 257 self.assertEqual('core', analysis.solution) | 226 self.assertEqual('core', analysis.solution) |
| 258 | 227 |
| 259 def testAnalysisAborted(self): | 228 def testAnalysisAborted(self): |
| 260 chrome_version = '1' | 229 analysis = FracasCrashAnalysis.Create(DUMMY_CRASH_IDENTIFIERS1) |
| 261 signature = 'signature' | |
| 262 platform = 'win' | |
| 263 crash_identifiers = { | |
| 264 'chrome_version': chrome_version, | |
| 265 'signature': signature, | |
| 266 'channel': 'canary', | |
| 267 'platform': platform, | |
| 268 'process_type': 'browser', | |
| 269 } | |
| 270 analysis = FracasCrashAnalysis.Create(crash_identifiers) | |
| 271 analysis.status = analysis_status.RUNNING | 230 analysis.status = analysis_status.RUNNING |
| 272 analysis.put() | 231 analysis.put() |
| 273 | 232 |
| 274 pipeline = crash_pipeline.CrashAnalysisPipeline(crash_identifiers, 'fracas') | 233 pipeline = crash_pipeline.CrashAnalysisPipeline(DUMMY_CRASH_IDENTIFIERS1, 'f racas') |
| 275 pipeline._SetErrorIfAborted(True) | 234 # TODO(wrengr): we can't actually set |was_aborted|, so we'll have to call | finalized()| some other way. Of re-factor it out again :( |
| 276 analysis = FracasCrashAnalysis.Get(crash_identifiers) | 235 pipeline.was_aborted = True |
|
stgao
2016/10/12 15:46:58
Yes, we have to go with the original approach for
wrengr
2016/10/12 21:14:51
Acknowledged.
| |
| 236 pipeline.finalized() | |
| 237 analysis = FracasCrashAnalysis.Get(DUMMY_CRASH_IDENTIFIERS1) | |
| 277 self.assertEqual(analysis_status.ERROR, analysis.status) | 238 self.assertEqual(analysis_status.ERROR, analysis.status) |
| OLD | NEW |