| OLD | NEW |
| (Empty) | |
| 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 |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import copy |
| 6 import logging |
| 7 |
| 8 from crash.crash_report import CrashReport |
| 9 from crash.culprit import NullCulprit |
| 10 from crash.findit_for_chromecrash import FinditForChromeCrash |
| 11 from crash.findit_for_chromecrash import FinditForFracas |
| 12 from crash.findit import Findit |
| 13 from crash.stacktrace import Stacktrace |
| 14 from crash.test.crash_pipeline_test import DummyCrashData |
| 15 from crash.test.crash_testcase import CrashTestCase |
| 16 from crash.type_enums import CrashClient |
| 17 from model import analysis_status |
| 18 from model.crash.fracas_crash_analysis import FracasCrashAnalysis |
| 19 |
| 20 # In production we'd use CrashWrapperPipeline. And that'd work fine here, |
| 21 # since we never actually call the method that uses it. But just to be |
| 22 # absolutely sure we don't go over the wire due to some mocking failure, |
| 23 # we'll use this dummy class instead. (In fact, since it's never used, |
| 24 # we don't even need to give a real class; |None| works just fine.) |
| 25 MOCK_PIPELINE_CLS = None |
| 26 |
| 27 def _FinditForFracas(): |
| 28 """A helper to pass in the standard pipeline class.""" |
| 29 return FinditForFracas(MOCK_PIPELINE_CLS) |
| 30 |
| 31 |
| 32 class UnsupportedClient(Findit): # pylint: disable=W0223 |
| 33 @property |
| 34 def client_id(self): |
| 35 return self._client_id |
| 36 |
| 37 def __init__(self, client_id=None): |
| 38 super(UnsupportedClient, self).__init__(MOCK_PIPELINE_CLS) |
| 39 if client_id is None: |
| 40 client_id = 'unsupported_client' |
| 41 self._client_id = client_id |
| 42 |
| 43 |
| 44 class FindTest(CrashTestCase): |
| 45 |
| 46 # TODO(wrengr): make this test more straightforward/immediate; or give |
| 47 # it a better name. |
| 48 def testPlatformRename(self): |
| 49 old_crash_data = DummyCrashData( |
| 50 version = None, |
| 51 platform = 'unix', |
| 52 crash_identifiers = {}) |
| 53 # This is just here to match the old tests. Shouldn't actually be necessary. |
| 54 del old_crash_data['customized_data']['historical_metadata'] |
| 55 |
| 56 testcase = self |
| 57 class _MockFindit(FinditForFracas): |
| 58 def __init__(self): |
| 59 super(_MockFindit, self).__init__(MOCK_PIPELINE_CLS) |
| 60 |
| 61 def _NeedsNewAnalysis(self, new_crash_data): |
| 62 testcase.assertEqual(self.client_id, CrashClient.FRACAS) |
| 63 testcase.assertDictEqual(new_crash_data, old_crash_data) |
| 64 return False |
| 65 |
| 66 new_crash_data = copy.deepcopy(old_crash_data) |
| 67 new_crash_data['platform'] = 'linux' |
| 68 self.assertFalse(_MockFindit().ScheduleNewAnalysis(new_crash_data)) |
| 69 |
| 70 def testCheckPolicyUnsupportedClient(self): |
| 71 self.assertIsNone(UnsupportedClient().CheckPolicy(DummyCrashData( |
| 72 platform = 'canary', |
| 73 signature = 'sig', |
| 74 ))) |
| 75 |
| 76 def testCheckPolicyUnsupportedPlatform(self): |
| 77 self.assertIsNone(_FinditForFracas().CheckPolicy(DummyCrashData( |
| 78 platform = 'unsupported_platform'))) |
| 79 |
| 80 def testCheckPolicyBlacklistedSignature(self): |
| 81 self.assertIsNone(_FinditForFracas().CheckPolicy(DummyCrashData( |
| 82 signature = 'Blacklist marker signature'))) |
| 83 |
| 84 def testCheckPolicyPlatformRename(self): |
| 85 new_crash_data = _FinditForFracas().CheckPolicy(DummyCrashData( |
| 86 platform = 'linux')) |
| 87 self.assertIsNotNone(new_crash_data, |
| 88 'FinditForFracas.CheckPolicy unexpectedly returned None') |
| 89 self.assertEqual(new_crash_data['platform'], 'unix') |
| 90 |
| 91 def testCreateAnalysisForFracas(self): |
| 92 self.assertIsNotNone(_FinditForFracas().CreateAnalysis( |
| 93 {'signature': 'sig'})) |
| 94 |
| 95 def testCreateAnalysisForUnsupportedClientId(self): |
| 96 self.assertIsNone(UnsupportedClient('unsupported_id').CreateAnalysis( |
| 97 {'signature': 'sig'})) |
| 98 |
| 99 def testGetAnalysisForFracas(self): |
| 100 crash_identifiers = {'signature': 'sig'} |
| 101 # TODO(wrengr): would be less fragile to call |
| 102 # FinditForFracas.CreateAnalysis instead. |
| 103 analysis = FracasCrashAnalysis.Create(crash_identifiers) |
| 104 analysis.put() |
| 105 self.assertEqual(_FinditForFracas().GetAnalysis(crash_identifiers), |
| 106 analysis) |
| 107 |
| 108 def testGetAnalysisForUnsuportedClient(self): |
| 109 crash_identifiers = {'signature': 'sig'} |
| 110 # TODO(wrengr): it'd be less fragile to call FinditForFracas.CreateAnalysis |
| 111 # instead. But we'd need to make UnsupportedClient inherit that |
| 112 # implementation then, rather than inheriting the one from the Findit |
| 113 # base class. |
| 114 analysis = FracasCrashAnalysis.Create(crash_identifiers) |
| 115 analysis.put() |
| 116 self.assertIsNone( |
| 117 UnsupportedClient('Unsupported_client').GetAnalysis(crash_identifiers), |
| 118 'Unsupported client unexpectedly got analysis %s via identifiers %s' |
| 119 % (analysis, crash_identifiers)) |
| 120 |
| 121 def testInitializeAnalysisForFracas(self): |
| 122 crash_data = DummyCrashData(platform = 'linux') |
| 123 crash_identifiers = crash_data['crash_identifiers'] |
| 124 |
| 125 findit_client = _FinditForFracas() |
| 126 analysis = findit_client.CreateAnalysis(crash_identifiers) |
| 127 findit_client._InitializeAnalysis(analysis, crash_data) |
| 128 analysis.put() |
| 129 analysis = findit_client.GetAnalysis(crash_identifiers) |
| 130 self.assertIsNotNone(analysis, |
| 131 'FinditForFracas.GetAnalysis unexpectedly returned None') |
| 132 |
| 133 self.assertEqual(analysis.crashed_version, crash_data['crashed_version']) |
| 134 self.assertEqual(analysis.signature, crash_data['signature']) |
| 135 self.assertEqual(analysis.platform, crash_data['platform']) |
| 136 self.assertEqual(analysis.stack_trace, crash_data['stack_trace']) |
| 137 channel = crash_data['customized_data'].get('channel', None) |
| 138 self.assertIsNotNone(channel, |
| 139 'channel is unexpectedly not defined in crash_data') |
| 140 self.assertEqual(analysis.channel, channel) |
| 141 |
| 142 # TODO(wrengr): what was the purpose of this test? As written it's |
| 143 # just testing that mocking works. I'm guessing it was to check that |
| 144 # we fail when the analysis is for the wrong client_id; but if so, |
| 145 # then we shouldn't need to mock FindCulprit... |
| 146 def testFindCulprit(self): |
| 147 self.mock(FinditForChromeCrash, 'FindCulprit', |
| 148 lambda self, *_: NullCulprit()) |
| 149 |
| 150 # TODO(wrengr): would be less fragile to call |
| 151 # FinditForFracas.CreateAnalysis instead; though if I'm right about |
| 152 # the original purpose of this test, then this is one of the few |
| 153 # places where calling FracasCrashAnalysis directly would actually |
| 154 # make sense. |
| 155 analysis = FracasCrashAnalysis.Create({'signature': 'sig'}) |
| 156 # TODO(wrengr): shouldn't FracasCrashAnalysis.Create already have set |
| 157 # the client_id? |
| 158 analysis.client_id = CrashClient.FRACAS |
| 159 |
| 160 # TODO(wrengr): just test for the NullCulprit directly; instead of |
| 161 # going through |ToDicts|. |
| 162 result, tags = FinditForChromeCrash(MOCK_PIPELINE_CLS |
| 163 ).FindCulprit(analysis).ToDicts() |
| 164 expected_result, expected_tags = NullCulprit().ToDicts() |
| 165 self.assertDictEqual(result, expected_result) |
| 166 self.assertDictEqual(tags, expected_tags) |
| 167 |
| 168 def testNeedsNewAnalysisIsTrueIfNoAnalysisYet(self): |
| 169 self.assertTrue(_FinditForFracas()._NeedsNewAnalysis(DummyCrashData())) |
| 170 |
| 171 def testNeedsNewAnalysisIsTrueIfLastOneFailed(self): |
| 172 crash_data = DummyCrashData() |
| 173 # TODO(wrengr): would be less fragile to call |
| 174 # FinditForFracas.CreateAnalysis instead. |
| 175 analysis = FracasCrashAnalysis.Create(crash_data['crash_identifiers']) |
| 176 analysis.status = analysis_status.ERROR |
| 177 analysis.put() |
| 178 self.assertTrue(_FinditForFracas()._NeedsNewAnalysis(crash_data)) |
| 179 |
| 180 def testNeedsNewAnalysisIsFalseIfLastOneIsNotFailed(self): |
| 181 crash_data = DummyCrashData() |
| 182 crash_identifiers = crash_data['crash_identifiers'] |
| 183 for status in (analysis_status.PENDING, analysis_status.RUNNING, |
| 184 analysis_status.COMPLETED, analysis_status.SKIPPED): |
| 185 # TODO(wrengr): would be less fragile to call |
| 186 # FinditForFracas.CreateAnalysis instead. |
| 187 analysis = FracasCrashAnalysis.Create(crash_identifiers) |
| 188 analysis.status = status |
| 189 analysis.put() |
| 190 self.assertFalse(_FinditForFracas()._NeedsNewAnalysis(crash_data)) |
| 191 |
| 192 def testScheduleNewAnalysisSkipsUnsupportedChannel(self): |
| 193 self.assertFalse(_FinditForFracas().ScheduleNewAnalysis(DummyCrashData( |
| 194 version = None, |
| 195 signature = None, |
| 196 crash_identifiers = {}, |
| 197 channel = 'unsupported_channel'))) |
| 198 |
| 199 def testScheduleNewAnalysisSkipsUnsupportedPlatform(self): |
| 200 self.assertFalse(_FinditForFracas().ScheduleNewAnalysis(DummyCrashData( |
| 201 version = None, |
| 202 signature = None, |
| 203 platform = 'unsupported_platform', |
| 204 crash_identifiers = {}))) |
| 205 |
| 206 def testScheduleNewAnalysisSkipsBlackListSignature(self): |
| 207 self.assertFalse(_FinditForFracas().ScheduleNewAnalysis(DummyCrashData( |
| 208 version = None, |
| 209 signature = 'Blacklist marker signature', |
| 210 crash_identifiers = {}))) |
| 211 |
| 212 def testScheduleNewAnalysisSkipsIfAlreadyCompleted(self): |
| 213 crash_data = DummyCrashData() |
| 214 crash_identifiers = crash_data['crash_identifiers'] |
| 215 # TODO(wrengr): would be less fragile to call |
| 216 # FinditForFracas.CreateAnalysis instead. |
| 217 analysis = FracasCrashAnalysis.Create(crash_identifiers) |
| 218 analysis.status = analysis_status.COMPLETED |
| 219 analysis.put() |
| 220 self.assertFalse(_FinditForFracas().ScheduleNewAnalysis(crash_data)) |
| OLD | NEW |