def _MockFetch(url=None): if start_try_job._BISECT_CONFIG_PATH in url: return testing_common.FakeResponseObject( 200, base64.encodestring(_BISECT_CONFIG_CONTENTS)) elif start_try_job._PERF_CONFIG_PATH in url: return testing_common.FakeResponseObject( 200, base64.encodestring(_PERF_CONFIG_CONTENTS))
def _MockMakeRequest(path, *args, **kwargs): # pylint: disable=unused-argument """Mocks out a request, returning a canned response.""" if path.endswith('xsrf_token'): assert kwargs['headers']['X-Requesting-XSRF-Token'] == 1 return testing_common.FakeResponseObject(200, _FAKE_XSRF_TOKEN) if path == 'upload': assert kwargs['method'] == 'POST' assert _EXPECTED_CONFIG_DIFF in kwargs['body'], ( '%s\nnot in\n%s\n' % (_EXPECTED_CONFIG_DIFF, kwargs['body'])) return testing_common.FakeResponseObject(200, _ISSUE_CREATED_RESPONSE) if path == '33001/upload_content/1/1001': assert kwargs['method'] == 'POST' assert _TEST_EXPECTED_CONFIG_CONTENTS in kwargs['body'] return testing_common.FakeResponseObject(200, 'Dummy content') if path == '33001/upload_complete/1': assert kwargs['method'] == 'POST' return testing_common.FakeResponseObject(200, 'Dummy content') if path == '33001/try/1': assert _TEST_EXPECTED_BOT in kwargs['body'] return testing_common.FakeResponseObject(200, 'Dummy content') assert False, 'Invalid url %s requested!' % path
def _MockFetch(url=None): url_to_response_map = { 'http://src.chromium.org/viewvc/chrome?view=revision&revision=20798': [200, _REVISION_RESPONSE], 'http://src.chromium.org/viewvc/chrome?view=revision&revision=20799': [200, 'REVISION REQUEST FAILED!'], 'https://codereview.chromium.org/api/17504006': [200, json.dumps(json.loads(_ISSUE_RESPONSE))], } if url not in url_to_response_map: assert False, 'Bad url %s' % url response_code = url_to_response_map[url][0] response = url_to_response_map[url][1] return testing_common.FakeResponseObject(response_code, response)
class EmailSheriffTest(testing_common.TestCase): def _AddTestToStubDataStore(self): """Adds a test which will be used in the methods below.""" bug_label_patterns.AddBugLabelPattern('label1', '*/*/dromaeo/dom') bug_label_patterns.AddBugLabelPattern('label2', '*/*/other/test') testing_common.AddTests( ['ChromiumPerf'], ['Win7'], {'dromaeo': {'dom': {}}}) test = utils.TestKey('ChromiumPerf/Win7/dromaeo/dom').get() test.improvement_direction = anomaly.DOWN return test def _GetDefaultMailArgs(self): """Adds an Anomaly and returns arguments for email_sheriff.EmailSheriff.""" test_entity = self._AddTestToStubDataStore() subscription_url = Subscription( name='Chromium Perf Sheriff URL', rotation_url=_SHERIFF_URL, bug_labels=['Performance-Sheriff-URL'] ) subscription_email = Subscription( name='Chromium Perf Sheriff Mail', notification_email=_SHERIFF_EMAIL, bug_labels=['Performance-Sheriff-Mail'] ) anomaly_entity = anomaly.Anomaly( median_before_anomaly=5.0, median_after_anomaly=10.0, start_revision=10002, end_revision=10004, subscription_names=[ subscription_url.name, subscription_email.name, ], subscriptions=[subscription_url, subscription_email], test=utils.TestKey('ChromiumPerf/Win7/dromaeo/dom')) return { 'subscriptions': [subscription_url, subscription_email], 'test': test_entity, 'anomaly': anomaly_entity } @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, 'document.write(\'sullivan\')'))) def testEmailSheriff_ContentAndRecipientAreCorrect(self): email_sheriff.EmailSheriff(**self._GetDefaultMailArgs()) messages = self.mail_stub.get_sent_messages() self.assertEqual(1, len(messages)) self.assertEqual('*****@*****.**', messages[0].sender) self.assertEqual( set(['*****@*****.**', '*****@*****.**']), set([s.strip() for s in messages[0].to.split(',')])) name = 'dromaeo/dom on Win7' expected_subject = '100.0%% regression in %s at 10002:10004' % name self.assertEqual(expected_subject, messages[0].subject) body = str(messages[0].body) self.assertIn('10002 - 10004', body) self.assertIn('100.0%', body) self.assertIn('ChromiumPerf', body) self.assertIn('Win7', body) self.assertIn('dromaeo/dom', body) html = str(messages[0].html) self.assertIn('<b>10002 - 10004</b>', html) self.assertIn('<b>100.0%</b>', html) self.assertIn('<b>ChromiumPerf</b>', html) self.assertIn('<b>Win7</b>', html) self.assertIn('<b>dromaeo/dom</b>', html) @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, 'document.write(\'sonnyrao, digit\')'))) def testEmailSheriff_MultipleSheriffs_AllGetEmailed(self): email_sheriff.EmailSheriff(**self._GetDefaultMailArgs()) messages = self.mail_stub.get_sent_messages() self.assertEqual(1, len(messages)) self.assertEqual('*****@*****.**', messages[0].sender) self.assertEqual( set(['*****@*****.**', '*****@*****.**', '*****@*****.**']), set([s.strip() for s in messages[0].to.split(',')])) def testEmail_NoSheriffUrl_EmailSentToSheriffRotationEmailAddress(self): args = self._GetDefaultMailArgs() args['subscriptions'][0].rotation_url = None email_sheriff.EmailSheriff(**args) messages = self.mail_stub.get_sent_messages() self.assertEqual(1, len(messages)) # An email is only sent to the general sheriff rotation email; # There is no other specific sheriff to send it to. self.assertEqual('*****@*****.**', messages[0].to) @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock( return_value=testing_common.FakeResponseObject(200, 'garbage'))) def testEmailSheriff_RotationUrlHasInvalidContent_EmailStillSent(self): """Tests the email to list when the rotation URL returns garbage.""" args = self._GetDefaultMailArgs() email_sheriff.EmailSheriff(**args) messages = self.mail_stub.get_sent_messages() self.assertEqual(1, len(messages)) # An email is only sent to the general sheriff rotation email. self.assertEqual('*****@*****.**', messages[0].to) def testEmailSheriff_PercentChangeMaxFloat_ContentSaysAlertSize(self): """Tests the email content for "freakin huge" alert.""" args = self._GetDefaultMailArgs() args['subscriptions'][0].rotation_url = None args['anomaly'].median_before_anomaly = 0.0 email_sheriff.EmailSheriff(**args) messages = self.mail_stub.get_sent_messages() self.assertEqual(1, len(messages)) self.assertIn(anomaly.FREAKIN_HUGE, str(messages[0].subject)) self.assertNotIn(str(sys.float_info.max), str(messages[0].body)) self.assertIn(anomaly.FREAKIN_HUGE, str(messages[0].body)) self.assertNotIn(str(sys.float_info.max), str(messages[0].html)) self.assertIn(anomaly.FREAKIN_HUGE, str(messages[0].html))
def _MockFetch(_): response_text = json.dumps({'key': 'this is well-formed JSON.'}) if base64_encoded: response_text = base64.b64encode(response_text) return testing_common.FakeResponseObject(status, response_text)
class FileBugTest(testing_common.TestCase): def setUp(self): super(FileBugTest, self).setUp() testing_common.SetSheriffDomains(['chromium.org']) testing_common.SetIsInternalUser('*****@*****.**', True) testing_common.SetIsInternalUser('*****@*****.**', False) self.SetCurrentUser('*****@*****.**') self._issue_tracker_service = testing_common.FakeIssueTrackerService() self.PatchObject(file_bug.file_bug.issue_tracker_service, 'IssueTrackerService', lambda *_: self._issue_tracker_service) app = webapp2.WSGIApplication([('/file_bug', file_bug.FileBugHandler)]) self.testapp = webtest.TestApp(app) def tearDown(self): super(FileBugTest, self).tearDown() self.UnsetCurrentUser() def _AddSampleAlerts(self, master='ChromiumPerf', has_commit_positions=True): """Adds sample data and returns a dict of rev to anomaly key.""" # Add sample sheriff, masters, bots, and tests. subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff'], bug_components=['Blink>Javascript'], ) testing_common.AddTests( [master], ['linux'], {'scrolling': { 'first_paint': {}, 'mean_frame_time': {}, }}) test_path1 = '%s/linux/scrolling/first_paint' % master test_path2 = '%s/linux/scrolling/mean_frame_time' % master test_key1 = utils.TestKey(test_path1) test_key2 = utils.TestKey(test_path2) anomaly_key1 = self._AddAnomaly(111995, 112005, test_key1, subscription) anomaly_key2 = self._AddAnomaly(112000, 112010, test_key2, subscription) anomaly_key3 = self._AddAnomaly(112015, 112015, test_key2, subscription) rows_1 = testing_common.AddRows(test_path1, [112005]) rows_2 = testing_common.AddRows(test_path2, [112010]) rows_2 = testing_common.AddRows(test_path2, [112015]) if has_commit_positions: rows_1[0].r_commit_pos = 112005 rows_2[0].r_commit_pos = 112010 return (anomaly_key1, anomaly_key2, anomaly_key3) def _AddSampleClankAlerts(self): """Adds sample data and returns a dict of rev to anomaly key. The biggest difference here is that the start/end revs aren't chromium commit positions. This tests the _MilestoneLabel function to make sure it will update the end_revision if r_commit_pos is found. """ # Add sample sheriff, masters, bots, and tests. Doesn't need to be Clank. subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff'], bug_components=['Blink>Javascript'], ) testing_common.AddTests( ['ChromiumPerf'], ['linux'], {'scrolling': { 'first_paint': {}, 'mean_frame_time': {}, }}) test_path1 = 'ChromiumPerf/linux/scrolling/first_paint' test_path2 = 'ChromiumPerf/linux/scrolling/mean_frame_time' test_key1 = utils.TestKey(test_path1) test_key2 = utils.TestKey(test_path2) anomaly_key1 = self._AddAnomaly(1476193324, 1476201840, test_key1, subscription) anomaly_key2 = self._AddAnomaly(1476193320, 1476201870, test_key2, subscription) anomaly_key3 = self._AddAnomaly(1476193390, 1476193390, test_key2, subscription) rows_1 = testing_common.AddRows(test_path1, [1476201840]) rows_2 = testing_common.AddRows(test_path2, [1476201870]) rows_3 = testing_common.AddRows(test_path2, [1476193390]) # These will be the revisions used to determine label. rows_1[0].r_commit_pos = 112005 rows_2[0].r_commit_pos = 112010 rows_3[0].r_commit_pos = 112015 return (anomaly_key1, anomaly_key2, anomaly_key3) def _AddAnomaly(self, start_rev, end_rev, test_key, subscription): return anomaly.Anomaly(start_revision=start_rev, end_revision=end_rev, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscription_names=[subscription.name], subscriptions=[subscription]).put() @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.app_identity.get_default_version_hostname', mock.MagicMock(return_value='chromeperf.appspot.com')) def testBisectDisabled(self): http = utils.ServiceAccountHttp() owner = '' cc = '*****@*****.**' summary = 'test' description = 'Test test.' project_id = None labels = [] components = [] test_path = 'ChromiumPerf/linux/scrolling/first_paint' test_key = utils.TestKey(test_path) subscription = Subscription(name='Sheriff', ) keys = [self._AddAnomaly(10, 20, test_key, subscription).urlsafe()] bisect = False result = file_bug.file_bug.FileBug(http, owner, cc, summary, description, project_id, labels, components, keys, bisect) self.assertNotIn('bisect_error', result) self.assertNotIn('jobId', result) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.app_identity.get_default_version_hostname', mock.MagicMock(return_value='chromeperf.appspot.com')) def testSupportsCCList(self): http = utils.ServiceAccountHttp() owner = '' cc = '[email protected],[email protected],[email protected],,' summary = 'test' description = 'Test test.' project_id = None labels = [] components = [] test_path = 'ChromiumPerf/linux/scrolling/first_paint' test_key = utils.TestKey(test_path) subscription = Subscription(name='Sheriff', ) keys = [self._AddAnomaly(10, 20, test_key, subscription).urlsafe()] bisect = False result = file_bug.file_bug.FileBug(http, owner, cc, summary, description, project_id, labels, components, keys, bisect) self.assertNotIn('bisect_error', result) self.assertNotIn('jobId', result) def testGet_WithNoKeys_ShowsError(self): # When a request is made and no keys parameter is given, # an error message is shown in the reply. response = self.testapp.get( '/file_bug?summary=s&description=d&finish=true') self.assertIn('<div class="error">', response.body) self.assertIn('No alerts specified', response.body) def testGet_WithNoFinish_ShowsForm(self): # When a GET request is sent with keys specified but the finish parameter # is not given, the response should contain a form for the sheriff to fill # in bug details (summary, description, etc). alert_keys = self._AddSampleAlerts() response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s' % alert_keys[0].urlsafe()) self.assertEqual(1, len(response.html('form'))) self.assertIn('<input name="cc" type="text" value="*****@*****.**">', str(response.html('form')[0])) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) def testInternalBugLabel(self): # If any of the alerts are marked as internal-only, which should happen # when the corresponding test is internal-only, then the create bug dialog # should suggest adding a Restrict-View-Google label. self.SetCurrentUser('*****@*****.**') alert_keys = self._AddSampleAlerts() anomaly_entity = alert_keys[0].get() anomaly_entity.internal_only = True anomaly_entity.put() response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s' % alert_keys[0].urlsafe()) self.assertIn('Restrict-View-Google', response.body) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) def testGet_SetsBugLabelsComponents(self): self.SetCurrentUser('*****@*****.**') alert_keys = self._AddSampleAlerts() bug_label_patterns.AddBugLabelPattern('label1-foo', '*/*/*/first_paint') bug_label_patterns.AddBugLabelPattern('Cr-Performance-Blink', '*/*/*/mean_frame_time') response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s,%s' % (alert_keys[0].urlsafe(), alert_keys[1].urlsafe())) self.assertIn('label1-foo', response.body) self.assertIn('Performance>Blink', response.body) self.assertIn('Performance-Sheriff', response.body) self.assertIn('Blink>Javascript', response.body) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.app_identity.get_default_version_hostname', mock.MagicMock(return_value='chromeperf.appspot.com')) @mock.patch.object(file_bug.file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def _PostSampleBug(self, has_commit_positions=True, master='ChromiumPerf', is_single_rev=False): if master == 'ClankInternal': alert_keys = self._AddSampleClankAlerts() else: alert_keys = self._AddSampleAlerts(master, has_commit_positions) if is_single_rev: alert_keys = alert_keys[2].urlsafe() else: alert_keys = '%s,%s' % (alert_keys[0].urlsafe(), alert_keys[1].urlsafe()) response = self.testapp.post('/file_bug', [ ('keys', alert_keys), ('summary', 's'), ('description', 'd\n'), ('finish', 'true'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) return response @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object(file_bug.file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def testGet_WithFinish_CreatesBug(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug() # The response page should have a bug number. self.assertIn('277761', response.body) # The anomaly entities should be updated. for anomaly_entity in anomaly.Anomaly.query().fetch(): if anomaly_entity.end_revision in [112005, 112010]: self.assertEqual(277761, anomaly_entity.bug_id) else: self.assertIsNone(anomaly_entity.bug_id) # Two HTTP requests are made when filing a bug; only test 2nd request. comment = self._issue_tracker_service.add_comment_args[1] self.assertIn( 'https://chromeperf.appspot.com/group_report?bug_id=277761', comment) self.assertIn('https://chromeperf.appspot.com/group_report?sid=', comment) self.assertIn( '\n\n\nBot(s) for this bug\'s original alert(s):\n\nlinux', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object(file_bug.file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def testGet_WithFinish_CreatesBug_WithDocs(self): diag_dict = generic_set.GenericSet( [[u'Benchmark doc link', u'http://docs']]) diag = histogram.SparseDiagnostic( data=diag_dict.AsDict(), start_revision=1, end_revision=sys.maxsize, name=reserved_infos.DOCUMENTATION_URLS.name, test=utils.TestKey('ChromiumPerf/linux/scrolling')) diag.put() # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug() # The response page should have a bug number. self.assertIn('277761', response.body) # The anomaly entities should be updated. for anomaly_entity in anomaly.Anomaly.query().fetch(): if anomaly_entity.end_revision in [112005, 112010]: self.assertEqual(277761, anomaly_entity.bug_id) else: self.assertIsNone(anomaly_entity.bug_id) # Two HTTP requests are made when filing a bug; only test 2nd request. comment = self._issue_tracker_service.add_comment_args[1] self.assertIn( 'https://chromeperf.appspot.com/group_report?bug_id=277761', comment) self.assertIn('https://chromeperf.appspot.com/group_report?sid=', comment) self.assertIn( '\n\n\nBot(s) for this bug\'s original alert(s):\n\nlinux', comment) self.assertIn('scrolling - Benchmark doc link:', comment) self.assertIn('http://docs', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object( file_bug.file_bug.crrev_service, 'GetNumbering', mock.MagicMock(return_value={ 'git_sha': '852ba7672ce02911e9f8f2a22363283adc80940e' })) @mock.patch( 'dashboard.services.gitiles_service.CommitInfo', mock.MagicMock(return_value={ 'author': { 'email': '*****@*****.**' }, 'message': 'My first commit!' })) def testGet_WithFinish_CreatesBugSingleRevOwner(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. namespaced_stored_object.Set( 'repositories', { "chromium": { "repository_url": "https://chromium.googlesource.com/chromium/src" } }) self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug(is_single_rev=True) # The response page should have a bug number. self.assertIn('277761', response.body) # Three HTTP requests are made when filing a bug with owner; test third # request for owner hame. comment = self._issue_tracker_service.add_comment_args[1] self.assertIn( 'Assigning to [email protected] because this is the only CL in range', comment) self.assertIn('My first commit', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object( file_bug.file_bug.crrev_service, 'GetNumbering', mock.MagicMock(return_value={ 'git_sha': '852ba7672ce02911e9f8f2a22363283adc80940e' })) @mock.patch('dashboard.services.gitiles_service.CommitInfo', mock.MagicMock( return_value={ 'author': { 'email': 'v8-ci-autoroll-builder@chops-service-' 'accounts.iam.gserviceaccount.com' }, 'message': 'This is a roll\n\[email protected]' })) def testGet_WithFinish_CreatesBugSingleRevAutorollOwner(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. namespaced_stored_object.Set( 'repositories', { "chromium": { "repository_url": "https://chromium.googlesource.com/chromium/src" } }) self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug(is_single_rev=True) # The response page should have a bug number. self.assertIn('277761', response.body) # Two HTTP requests are made when filing a bug; only test 2nd request. comment = self._issue_tracker_service.add_comment_args[1] self.assertIn('Assigning to [email protected]', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) def testGet_WithFinish_SingleRevOwner_Clank_Skips(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. namespaced_stored_object.Set( 'repositories', { "chromium": { "repository_url": "https://chromium.googlesource.com/chromium/src" } }) self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug(is_single_rev=True, master='ClankInternal') # The response page should have a bug number. self.assertIn('277761', response.body) # Three HTTP requests are made when filing a bug with owner; test third # request for owner hame. comment = self._issue_tracker_service.add_comment_args[1] self.assertNotIn( 'Assigning to [email protected] because this is the only CL in range', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) def testGet_WithFinish_SingleRevOwner_InvalidRepository_Skips(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. namespaced_stored_object.Set( 'repositories', { "chromium": { "repository_url": "https://chromium.googlesource.com/chromium/src" } }) self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug(is_single_rev=True, master='FakeMaster') # The response page should have a bug number. self.assertIn('277761', response.body) # Three HTTP requests are made when filing a bug with owner; test third # request for owner hame. comment = self._issue_tracker_service.add_comment_args[1] self.assertNotIn( 'Assigning to [email protected] because this is the only CL in range', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object( file_bug.file_bug.crrev_service, 'GetNumbering', mock.MagicMock(return_value={ 'git_sha': '852ba7672ce02911e9f8f2a22363283adc80940e' })) @mock.patch( 'dashboard.services.gitiles_service.CommitInfo', mock.MagicMock(return_value={ 'author': { 'email': '*****@*****.**' }, 'message': 'My first commit!' })) def testGet_WithFinish_CreatesBugSingleRevDifferentMasterOwner(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. namespaced_stored_object.Set( 'repositories', { "chromium": { "repository_url": "https://chromium.googlesource.com/chromium/src" } }) self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug(is_single_rev=True, master='Foo') # The response page should have a bug number. self.assertIn('277761', response.body) # Three HTTP requests are made when filing a bug with owner; test third # request for owner hame. comment = self._issue_tracker_service.add_comment_args[1] self.assertNotIn( 'Assigning to [email protected] because this is the only CL in range', comment) self.assertNotIn('My first commit', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object( file_bug.file_bug.crrev_service, 'GetNumbering', mock.MagicMock(return_value={ 'git_sha': '852ba7672ce02911e9f8f2a22363283adc80940e' })) @mock.patch('dashboard.services.gitiles_service.CommitInfo', mock.MagicMock( return_value={ 'author': { 'email': 'robot@chops-service-accounts' '.iam.gserviceaccount.com' }, 'message': 'This is an autoroll\n\[email protected]', })) def testGet_WithFinish_CreatesBugSingleRevAutorollSheriff(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. namespaced_stored_object.Set( 'repositories', { "chromium": { "repository_url": "https://chromium.googlesource.com/chromium/src" } }) self._issue_tracker_service._bug_id_counter = 277761 response = self._PostSampleBug(is_single_rev=True) # The response page should have a bug number. self.assertIn('277761', response.body) # Three HTTP requests are made when filing a bug with owner; test third # request for owner hame. comment = self._issue_tracker_service.add_comment_args[1] self.assertIn( 'Assigning to [email protected] because this is the only CL in range', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[{ 'versions': [{ 'branch_base_position': '112000', 'current_version': '2.0' }, { 'branch_base_position': '111990', 'current_version': '1.0' }] }])) @mock.patch.object(file_bug.file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def testGet_WithFinish_LabelsBugWithMilestone(self): # Here, we expect the bug to have the following end revisions: # [112005, 112010] and the milestones are M-1 for rev 111990 and # M-2 for 11200. Hence the expected behavior is to label the bug # M-2 since 111995 (lowest possible revision introducing regression) # is less than 112010 (revision for M-2). self._PostSampleBug() self.assertIn('M-2', self._issue_tracker_service.new_bug_kwargs['labels']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[{ 'versions': [{ 'branch_base_position': '112000', 'current_version': '2.0' }, { 'branch_base_position': '111990', 'current_version': '1.0' }] }])) @mock.patch.object(file_bug.file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def testGet_WithFinish_LabelsBugWithNoMilestoneBecauseNoCommitPos(self): # Here, we expect to return no Milestone label because the alerts do not # contain r_commit_pos (and therefore aren't chromium). Assuming # testGet_WithFinish_LabelsBugWithMilestone passes, M-2 # would be the label that it would get if the alert was Chromium. self._PostSampleBug(has_commit_positions=False) labels = self._issue_tracker_service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object(file_bug.file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[{ 'versions': [{ 'branch_base_position': '113000', 'current_version': '2.0' }, { 'branch_base_position': '112000', 'current_version': '2.0' }, { 'branch_base_position': '111990', 'current_version': '1.0' }] }])) @mock.patch.object(file_bug.file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def testGet_WithFinish_LabelsBugForClank(self): # Here, we expect to return M-2 even though the alert revisions aren't # even close to the branching points. We use r_commmit_pos to determine # which revision to check. There are 3 branching points to ensure we are # actually changing the revision that is checked to r_commit_pos instead # of just displaying the highest one (previous behavior). self._PostSampleBug(master='ClankInternal') self.assertIn('M-2', self._issue_tracker_service.new_bug_kwargs['labels']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock( return_value=testing_common.FakeResponseObject(200, '[]'))) def testGet_WithFinish_SucceedsWithNoVersions(self): # Here, we test that we don't label the bug with an unexpected value when # there is no version information from omahaproxy (for whatever reason) self._PostSampleBug() labels = self._issue_tracker_service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock( return_value=testing_common.FakeResponseObject(200, '[]'))) def testGet_WithFinish_SucceedsWithComponents(self): # Here, we test that components are posted separately from labels. self._PostSampleBug() self.assertIn('Foo>Bar', self._issue_tracker_service.new_bug_kwargs['components']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([{ 'versions': [{ 'branch_base_position': '0', 'current_version': '1.0' }] }])))) def testGet_WithFinish_SucceedsWithRevisionOutOfRange(self): # Here, we test that we label the bug with the highest milestone when the # revision introducing regression is beyond all milestones in the list. self._PostSampleBug() self.assertIn('M-1', self._issue_tracker_service.new_bug_kwargs['labels']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([{ 'versions': [{ 'branch_base_position': 'N/A', 'current_version': 'N/A' }] }])))) @mock.patch('logging.warn') def testGet_WithFinish_SucceedsWithNAAndLogsWarning(self, mock_warn): self._PostSampleBug() labels = self._issue_tracker_service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) self.assertEqual(1, mock_warn.call_count) def testGet_OwnersAreEmptyEvenWithOwnership(self): ownership_samples = [{ 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'emails': ['*****@*****.**'] }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'emails': ['*****@*****.**'] }] test_paths = [ 'ChromiumPerf/linux/scrolling/first_paint', 'ChromiumPerf/linux/scrolling/mean_frame_time' ] test_keys = [utils.TestKey(test_path) for test_path in test_paths] subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff', 'Cr-Blink-Javascript']) anomaly_1 = anomaly.Anomaly(start_revision=1476193324, end_revision=1476201840, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[0]).put() anomaly_2 = anomaly.Anomaly(start_revision=1476193320, end_revision=1476201870, test=test_keys[1], median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[1]).put() response = self.testapp.post('/file_bug', [ ('keys', '%s,%s' % (anomaly_1.urlsafe(), anomaly_2.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn('<input type="text" name="owner" value="">', response.body) response_changed_order = self.testapp.post('/file_bug', [ ('keys', '%s,%s' % (anomaly_2.urlsafe(), anomaly_1.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn('<input type="text" name="owner" value="">', response_changed_order.body) def testGet_OwnersNotFilledWhenNoOwnership(self): test_key = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint') subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff', 'Cr-Blink-Javascript']) anomaly_entity = anomaly.Anomaly( start_revision=1476193324, end_revision=1476201840, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ).put() response = self.testapp.post('/file_bug', [ ('keys', '%s' % (anomaly_entity.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn('<input type="text" name="owner" value="">', response.body) def testGet_WithAllOwnershipComponents(self): ownership_samples = [{ 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': 'Abc>Xyz' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'component': 'Def>123' }] test_paths = [ 'ChromiumPerf/linux/scrolling/first_paint', 'ChromiumPerf/linux/scrolling/mean_frame_time' ] test_keys = [utils.TestKey(test_path) for test_path in test_paths] subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff', 'Cr-Blink-Javascript']) anomaly_1 = anomaly.Anomaly(start_revision=1476193324, end_revision=1476201840, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[0]).put() anomaly_2 = anomaly.Anomaly(start_revision=1476193320, end_revision=1476201870, test=test_keys[1], median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[1]).put() response = self.testapp.post('/file_bug', [ ('keys', '%s' % (anomaly_1.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Xyz">', response.body) response_with_both_anomalies = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (anomaly_1.urlsafe(), anomaly_2.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Xyz">', response_with_both_anomalies.body) self.assertIn( '<input type="checkbox" checked name="component" value="Def>123">', response_with_both_anomalies.body) def testGet_UsesOnlyMostRecentComponents(self): ownership_samples = [ { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'component': 'Abc>Def' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': '123>456' }, ] subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff', 'Cr-Blink-Javascript']) test_key = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint') now_datetime = datetime.datetime.now() older_alert = anomaly.Anomaly(start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[0], timestamp=now_datetime).put() newer_alert = anomaly.Anomaly(start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[1], timestamp=now_datetime + datetime.timedelta(10)).put() response = self.testapp.post('/file_bug', [ ('keys', '%s,%s' % (older_alert.urlsafe(), newer_alert.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertNotIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response.body) self.assertIn( '<input type="checkbox" checked name="component" value="123>456">', response.body) response_inverted_order = self.testapp.post('/file_bug', [ ('keys', '%s,%s' % (newer_alert.urlsafe(), older_alert.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertNotIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response_inverted_order.body) self.assertIn( '<input type="checkbox" checked name="component" value="123>456">', response_inverted_order.body) def testGet_ComponentsChosenPerTest(self): ownership_samples = [ { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'component': 'Abc>Def' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': '123>456' }, ] subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff', 'Cr-Blink-Javascript']) test_paths = [ 'ChromiumPerf/linux/scrolling/first_paint', 'ChromiumPerf/linux/scrolling/mean_frame_time' ] test_keys = [utils.TestKey(test_path) for test_path in test_paths] now_datetime = datetime.datetime.now() alert_test_key_0 = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[0], timestamp=now_datetime).put() alert_test_key_1 = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_keys[1], median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[1], timestamp=now_datetime + datetime.timedelta(10)).put() response = self.testapp.post('/file_bug', [ ('keys', '%s,%s' % (alert_test_key_0.urlsafe(), alert_test_key_1.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response.body) self.assertIn( '<input type="checkbox" checked name="component" value="123>456">', response.body) def testGet_UsesFirstDefinedComponent(self): ownership_samples = [{ 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': '' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': 'Abc>Def' }] now_datetime = datetime.datetime.now() test_key = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint') subscription = Subscription( name='Sheriff', bug_labels=['Performance-Sheriff', 'Cr-Blink-Javascript']) alert_without_ownership = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], timestamp=now_datetime).put() alert_without_component = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[0], timestamp=now_datetime + datetime.timedelta(10)).put() alert_with_empty_component = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[1], timestamp=now_datetime + datetime.timedelta(20)).put() alert_with_component = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, subscriptions=[subscription], subscription_names=[subscription.name], ownership=ownership_samples[2], timestamp=now_datetime + datetime.timedelta(30)).put() response = self.testapp.post('/file_bug', [ ('keys', '%s,%s,%s,%s' % (alert_without_ownership.urlsafe(), alert_without_component.urlsafe(), alert_with_empty_component.urlsafe(), alert_with_component.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response.body)
class FileBugTest(testing_common.TestCase): def setUp(self): super(FileBugTest, self).setUp() app = webapp2.WSGIApplication([('/file_bug', file_bug.FileBugHandler)]) self.testapp = webtest.TestApp(app) testing_common.SetSheriffDomains(['chromium.org']) testing_common.SetIsInternalUser('*****@*****.**', True) testing_common.SetIsInternalUser('*****@*****.**', False) self.SetCurrentUser('*****@*****.**') # Add a fake issue tracker service that we can get call values from. file_bug.issue_tracker_service = mock.MagicMock() self.original_service = file_bug.issue_tracker_service.IssueTrackerService self.service = MockIssueTrackerService file_bug.issue_tracker_service.IssueTrackerService = self.service def tearDown(self): super(FileBugTest, self).tearDown() file_bug.issue_tracker_service.IssueTrackerService = self.original_service self.UnsetCurrentUser() def _AddSampleAlerts(self, is_chromium=True): """Adds sample data and returns a dict of rev to anomaly key.""" # Add sample sheriff, masters, bots, and tests. sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() testing_common.AddTests(['ChromiumPerf'], ['linux'], { 'scrolling': { 'first_paint': {}, 'mean_frame_time': {}, } }) test_path1 = 'ChromiumPerf/linux/scrolling/first_paint' test_path2 = 'ChromiumPerf/linux/scrolling/mean_frame_time' test_key1 = utils.TestKey(test_path1) test_key2 = utils.TestKey(test_path2) anomaly_key1 = self._AddAnomaly(111995, 112005, test_key1, sheriff_key) anomaly_key2 = self._AddAnomaly(112000, 112010, test_key2, sheriff_key) rows_1 = testing_common.AddRows(test_path1, [112005]) rows_2 = testing_common.AddRows(test_path2, [112010]) if is_chromium: rows_1[0].r_commit_pos = 112005 rows_2[0].r_commit_pos = 112010 return (anomaly_key1, anomaly_key2) def _AddSampleClankAlerts(self): """Adds sample data and returns a dict of rev to anomaly key. The biggest difference here is that the start/end revs aren't chromium commit positions. This tests the _MilestoneLabel function to make sure it will update the end_revision if r_commit_pos is found. """ # Add sample sheriff, masters, bots, and tests. Doesn't need to be Clank. sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() testing_common.AddTests(['ChromiumPerf'], ['linux'], { 'scrolling': { 'first_paint': {}, 'mean_frame_time': {}, } }) test_path1 = 'ChromiumPerf/linux/scrolling/first_paint' test_path2 = 'ChromiumPerf/linux/scrolling/mean_frame_time' test_key1 = utils.TestKey(test_path1) test_key2 = utils.TestKey(test_path2) anomaly_key1 = self._AddAnomaly(1476193324, 1476201840, test_key1, sheriff_key) anomaly_key2 = self._AddAnomaly(1476193320, 1476201870, test_key2, sheriff_key) rows_1 = testing_common.AddRows(test_path1, [1476201840]) rows_2 = testing_common.AddRows(test_path2, [1476201870]) # These will be the revisions used to determine label. rows_1[0].r_commit_pos = 112005 rows_2[0].r_commit_pos = 112010 return (anomaly_key1, anomaly_key2) def _AddAnomaly(self, start_rev, end_rev, test_key, sheriff_key): return anomaly.Anomaly( start_revision=start_rev, end_revision=end_rev, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key).put() def testGet_WithNoKeys_ShowsError(self): # When a request is made and no keys parameter is given, # an error message is shown in the reply. response = self.testapp.get( '/file_bug?summary=s&description=d&finish=true') self.assertIn('<div class="error">', response.body) self.assertIn('No alerts specified', response.body) def testGet_WithNoFinish_ShowsForm(self): # When a GET request is sent with keys specified but the finish parameter # is not given, the response should contain a form for the sheriff to fill # in bug details (summary, description, etc). alert_keys = self._AddSampleAlerts() response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s' % alert_keys[0].urlsafe()) self.assertEqual(1, len(response.html('form'))) self.assertIn('<input name="cc" type="text" value="*****@*****.**">', str(response.html('form')[0])) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) def testInternalBugLabel(self): # If any of the alerts are marked as internal-only, which should happen # when the corresponding test is internal-only, then the create bug dialog # should suggest adding a Restrict-View-Google label. self.SetCurrentUser('*****@*****.**') alert_keys = self._AddSampleAlerts() anomaly_entity = alert_keys[0].get() anomaly_entity.internal_only = True anomaly_entity.put() response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s' % alert_keys[0].urlsafe()) self.assertIn('Restrict-View-Google', response.body) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) def testGet_SetsBugLabelsComponents(self): self.SetCurrentUser('*****@*****.**') alert_keys = self._AddSampleAlerts() bug_label_patterns.AddBugLabelPattern('label1-foo', '*/*/*/first_paint') bug_label_patterns.AddBugLabelPattern('Cr-Performance-Blink', '*/*/*/mean_frame_time') response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s,%s' % ( alert_keys[0].urlsafe(), alert_keys[1].urlsafe())) self.assertIn('label1-foo', response.body) self.assertIn('Performance>Blink', response.body) self.assertIn('Performance-Sheriff', response.body) self.assertIn('Blink>Javascript', response.body) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.app_identity.get_default_version_hostname', mock.MagicMock(return_value='chromeperf.appspot.com')) @mock.patch.object( file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={'issue_id': 123, 'issue_url': 'foo.com'})) def _PostSampleBug(self, is_chromium=True, is_clankium=False): if is_clankium: alert_keys = self._AddSampleClankAlerts() else: alert_keys = self._AddSampleAlerts(is_chromium) response = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (alert_keys[0].urlsafe(), alert_keys[1].urlsafe())), ('summary', 's'), ('description', 'd\n'), ('finish', 'true'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) return response @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object( file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object( file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={'issue_id': 123, 'issue_url': 'foo.com'})) def testGet_WithFinish_CreatesBug(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. self.service.bug_id = 277761 response = self._PostSampleBug() # The response page should have a bug number. self.assertIn('277761', response.body) # The anomaly entities should be updated. for anomaly_entity in anomaly.Anomaly.query().fetch(): if anomaly_entity.end_revision in [112005, 112010]: self.assertEqual(277761, anomaly_entity.bug_id) else: self.assertIsNone(anomaly_entity.bug_id) # Two HTTP requests are made when filing a bug; only test 2nd request. comment = self.service.add_comment_args[1] self.assertIn( 'https://chromeperf.appspot.com/group_report?bug_id=277761', comment) self.assertIn('https://chromeperf.appspot.com/group_report?sid=', comment) self.assertIn( '\n\n\nBot(s) for this bug\'s original alert(s):\n\nlinux', comment) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object( file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[ { 'versions': [ {'branch_base_position': '112000', 'current_version': '2.0'}, {'branch_base_position': '111990', 'current_version': '1.0'} ] } ])) @mock.patch.object( file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={'issue_id': 123, 'issue_url': 'foo.com'})) def testGet_WithFinish_LabelsBugWithMilestone(self): # Here, we expect the bug to have the following end revisions: # [112005, 112010] and the milestones are M-1 for rev 111990 and # M-2 for 11200. Hence the expected behavior is to label the bug # M-2 since 111995 (lowest possible revision introducing regression) # is less than 112010 (revision for M-2). self._PostSampleBug() self.assertIn('M-2', self.service.new_bug_kwargs['labels']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @unittest.skip('Flaky; see #1555.') @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([ { 'versions': [ {'branch_base_position': '111999', 'current_version': '3.0.1234.32'}, {'branch_base_position': '112000', 'current_version': '2.0'}, {'branch_base_position': '111990', 'current_version': '1.0'} ] } ])))) def testGet_WithFinish_LabelsBugWithLowestMilestonePossible(self): # Here, we expect the bug to have the following start revisions: # [111995, 112005] and the milestones are M-1 for rev 111990, M-2 # for 112000 and M-3 for 111999. Hence the expected behavior is to # label the bug M-2 since 111995 is less than 112000 (M-2) and 111999 # (M-3) AND M-2 is lower than M-3. self._PostSampleBug() self.assertIn('M-2', self.service.new_bug_kwargs['labels']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object( file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[ { 'versions': [ {'branch_base_position': '112000', 'current_version': '2.0'}, {'branch_base_position': '111990', 'current_version': '1.0'} ] } ])) @mock.patch.object( file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={'issue_id': 123, 'issue_url': 'foo.com'})) def testGet_WithFinish_LabelsBugWithNoMilestoneBecauseNotChromium(self): # Here, we expect to return no Milestone label because the alerts do not # contain r_commit_pos (and therefore aren't chromium). Assuming # testGet_WithFinish_LabelsBugWithMilestone passes, M-2 # would be the label that it would get if the alert was Chromium. self._PostSampleBug(is_chromium=False) labels = self.service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch.object( file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[ { 'versions': [ {'branch_base_position': '113000', 'current_version': '2.0'}, {'branch_base_position': '112000', 'current_version': '2.0'}, {'branch_base_position': '111990', 'current_version': '1.0'} ] } ])) @mock.patch.object( file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={'issue_id': 123, 'issue_url': 'foo.com'})) def testGet_WithFinish_LabelsBugForClank(self): # Here, we expect to return M-2 even though the alert revisions aren't # even close to the branching points. We use r_commmit_pos to determine # which revision to check. There are 3 branching points to ensure we are # actually changing the revision that is checked to r_commit_pos instead # of just displaying the highest one (previous behavior). self._PostSampleBug(is_clankium=True) self.assertIn('M-2', self.service.new_bug_kwargs['labels']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, '[]'))) def testGet_WithFinish_SucceedsWithNoVersions(self): # Here, we test that we don't label the bug with an unexpected value when # there is no version information from omahaproxy (for whatever reason) self._PostSampleBug() labels = self.service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, '[]'))) def testGet_WithFinish_SucceedsWithComponents(self): # Here, we test that components are posted separately from labels. self._PostSampleBug() self.assertIn('Foo>Bar', self.service.new_bug_kwargs['components']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([ { 'versions': [ {'branch_base_position': '0', 'current_version': '1.0'} ] } ])))) def testGet_WithFinish_SucceedsWithRevisionOutOfRange(self): # Here, we test that we label the bug with the highest milestone when the # revision introducing regression is beyond all milestones in the list. self._PostSampleBug() self.assertIn('M-1', self.service.new_bug_kwargs['labels']) @mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock()) @mock.patch( 'google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([ { 'versions': [ {'branch_base_position': 'N/A', 'current_version': 'N/A'} ] } ])))) @mock.patch('logging.warn') def testGet_WithFinish_SucceedsWithNAAndLogsWarning(self, mock_warn): self._PostSampleBug() labels = self.service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) self.assertEqual(1, mock_warn.call_count) def testGet_OwnersAreEmptyEvenWithOwnership(self): ownership_samples = [ { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'emails': ['*****@*****.**'] }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'emails': ['*****@*****.**'] } ] test_paths = ['ChromiumPerf/linux/scrolling/first_paint', 'ChromiumPerf/linux/scrolling/mean_frame_time'] test_keys = [utils.TestKey(test_path) for test_path in test_paths] sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() anomaly_1 = anomaly.Anomaly( start_revision=1476193324, end_revision=1476201840, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[0]).put() anomaly_2 = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_keys[1], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[1]).put() response = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (anomaly_1.urlsafe(), anomaly_2.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="text" name="owner" value="">', response.body) response_changed_order = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (anomaly_2.urlsafe(), anomaly_1.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="text" name="owner" value="">', response_changed_order.body) def testGet_OwnersNotFilledWhenNoOwnership(self): test_key = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint') sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() anomaly_entity = anomaly.Anomaly( start_revision=1476193324, end_revision=1476201840, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key).put() response = self.testapp.post( '/file_bug', [ ('keys', '%s' % (anomaly_entity.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="text" name="owner" value="">', response.body) def testGet_WithAllOwnershipComponents(self): ownership_samples = [ { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': 'Abc>Xyz' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'component': 'Def>123' } ] test_paths = ['ChromiumPerf/linux/scrolling/first_paint', 'ChromiumPerf/linux/scrolling/mean_frame_time'] test_keys = [utils.TestKey(test_path) for test_path in test_paths] sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() anomaly_1 = anomaly.Anomaly( start_revision=1476193324, end_revision=1476201840, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[0]).put() anomaly_2 = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_keys[1], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[1]).put() response = self.testapp.post( '/file_bug', [ ('keys', '%s' % (anomaly_1.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Xyz">', response.body) response_with_both_anomalies = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (anomaly_1.urlsafe(), anomaly_2.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Xyz">', response_with_both_anomalies.body) self.assertIn( '<input type="checkbox" checked name="component" value="Def>123">', response_with_both_anomalies.body) def testGet_UsesOnlyMostRecentComponents(self): ownership_samples = [ { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'component': 'Abc>Def' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': '123>456' }, ] sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() test_key = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint') now_datetime = datetime.datetime.now() older_alert = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[0], timestamp=now_datetime).put() newer_alert = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[1], timestamp=now_datetime + datetime.timedelta(10)).put() response = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (older_alert.urlsafe(), newer_alert.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertNotIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response.body) self.assertIn( '<input type="checkbox" checked name="component" value="123>456">', response.body) response_inverted_order = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (newer_alert.urlsafe(), older_alert.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertNotIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response_inverted_order.body) self.assertIn( '<input type="checkbox" checked name="component" value="123>456">', response_inverted_order.body) def testGet_ComponentsChosenPerTest(self): ownership_samples = [ { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', 'component': 'Abc>Def' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': '123>456' }, ] sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() test_paths = ['ChromiumPerf/linux/scrolling/first_paint', 'ChromiumPerf/linux/scrolling/mean_frame_time'] test_keys = [utils.TestKey(test_path) for test_path in test_paths] now_datetime = datetime.datetime.now() alert_test_key_0 = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[0], timestamp=now_datetime).put() alert_test_key_1 = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_keys[1], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[1], timestamp=now_datetime + datetime.timedelta(10)).put() response = self.testapp.post( '/file_bug', [ ('keys', '%s,%s' % (alert_test_key_0.urlsafe(), alert_test_key_1.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response.body) self.assertIn( '<input type="checkbox" checked name="component" value="123>456">', response.body) def testGet_UsesFirstDefinedComponent(self): ownership_samples = [ { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827', }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': '' }, { 'type': 'Ownership', 'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826', 'component': 'Abc>Def' } ] now_datetime = datetime.datetime.now() test_key = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint') sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() alert_without_ownership = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, timestamp=now_datetime).put() alert_without_component = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[0], timestamp=now_datetime + datetime.timedelta(10)).put() alert_with_empty_component = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[1], timestamp=now_datetime + datetime.timedelta(20)).put() alert_with_component = anomaly.Anomaly( start_revision=1476193320, end_revision=1476201870, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, ownership=ownership_samples[2], timestamp=now_datetime + datetime.timedelta(30)).put() response = self.testapp.post( '/file_bug', [ ('keys', '%s,%s,%s,%s' % (alert_without_ownership.urlsafe(), alert_without_component.urlsafe(), alert_with_empty_component.urlsafe(), alert_with_component.urlsafe())), ('summary', 's'), ('description', 'd\n'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) self.assertIn( '<input type="checkbox" checked name="component" value="Abc>Def">', response.body)
def _MockFailedFetch(url=None): # pylint: disable=unused-argument return testing_common.FakeResponseObject(404, {})
class FileBugTest(testing_common.TestCase): def setUp(self): super(FileBugTest, self).setUp() app = webapp2.WSGIApplication([('/file_bug', file_bug.FileBugHandler)]) self.testapp = webtest.TestApp(app) testing_common.SetSheriffDomains(['chromium.org']) testing_common.SetIsInternalUser('*****@*****.**', True) testing_common.SetIsInternalUser('*****@*****.**', False) self.SetCurrentUser('*****@*****.**') # Add a fake issue tracker service that we can get call values from. file_bug.issue_tracker_service = mock.MagicMock() self.original_service = file_bug.issue_tracker_service.IssueTrackerService self.service = MockIssueTrackerService file_bug.issue_tracker_service.IssueTrackerService = self.service def tearDown(self): super(FileBugTest, self).tearDown() file_bug.issue_tracker_service.IssueTrackerService = self.original_service self.UnsetCurrentUser() def _AddSampleAlerts(self): """Adds sample data and returns a dict of rev to anomaly key.""" # Add sample sheriff, masters, bots, and tests. sheriff_key = sheriff.Sheriff( id='Sheriff', labels=['Performance-Sheriff', 'Cr-Blink-Javascript']).put() testing_common.AddTests( ['ChromiumPerf'], ['linux'], {'scrolling': { 'first_paint': {}, 'mean_frame_time': {}, }}) test_key1 = utils.TestKey('ChromiumPerf/linux/scrolling/first_paint') test_key2 = utils.TestKey( 'ChromiumPerf/linux/scrolling/mean_frame_time') anomaly_key1 = self._AddAnomaly(111995, 112005, test_key1, sheriff_key) anomaly_key2 = self._AddAnomaly(112000, 112010, test_key2, sheriff_key) return (anomaly_key1, anomaly_key2) def _AddAnomaly(self, start_rev, end_rev, test_key, sheriff_key): return anomaly.Anomaly(start_revision=start_rev, end_revision=end_rev, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key).put() def testGet_WithNoKeys_ShowsError(self): # When a request is made and no keys parameter is given, # an error message is shown in the reply. response = self.testapp.get( '/file_bug?summary=s&description=d&finish=true') self.assertIn('<div class="error">', response.body) self.assertIn('No alerts specified', response.body) def testGet_WithNoFinish_ShowsForm(self): # When a GET request is sent with keys specified but the finish parameter # is not given, the response should contain a form for the sheriff to fill # in bug details (summary, description, etc). alert_keys = self._AddSampleAlerts() response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s' % alert_keys[0].urlsafe()) self.assertEqual(1, len(response.html('form'))) self.assertIn('<input name="cc" type="text" value="*****@*****.**">', str(response.html('form')[0])) def testInternalBugLabel(self): # If any of the alerts are marked as internal-only, which should happen # when the corresponding test is internal-only, then the create bug dialog # should suggest adding a Restrict-View-Google label. self.SetCurrentUser('*****@*****.**') alert_keys = self._AddSampleAlerts() anomaly_entity = alert_keys[0].get() anomaly_entity.internal_only = True anomaly_entity.put() response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s' % alert_keys[0].urlsafe()) self.assertIn('Restrict-View-Google', response.body) def testGet_SetsBugLabelsComponents(self): self.SetCurrentUser('*****@*****.**') alert_keys = self._AddSampleAlerts() bug_label_patterns.AddBugLabelPattern('label1-foo', '*/*/*/first_paint') bug_label_patterns.AddBugLabelPattern('Cr-Performance-Blink', '*/*/*/mean_frame_time') response = self.testapp.get( '/file_bug?summary=s&description=d&keys=%s,%s' % (alert_keys[0].urlsafe(), alert_keys[1].urlsafe())) self.assertIn('label1-foo', response.body) self.assertIn('Performance>Blink', response.body) self.assertIn('Performance-Sheriff', response.body) self.assertIn('Blink>Javascript', response.body) @mock.patch( 'google.appengine.api.app_identity.get_default_version_hostname', mock.MagicMock(return_value='chromeperf.appspot.com')) @mock.patch.object(file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def _PostSampleBug(self): alert_keys = self._AddSampleAlerts() response = self.testapp.post('/file_bug', [ ('keys', '%s,%s' % (alert_keys[0].urlsafe(), alert_keys[1].urlsafe())), ('summary', 's'), ('description', 'd\n'), ('finish', 'true'), ('label', 'one'), ('label', 'two'), ('component', 'Foo>Bar'), ]) return response @mock.patch.object(file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[])) @mock.patch.object(file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def testGet_WithFinish_CreatesBug(self): # When a POST request is sent with keys specified and with the finish # parameter given, an issue will be created using the issue tracker # API, and the anomalies will be updated, and a response page will # be sent which indicates success. self.service.bug_id = 277761 response = self._PostSampleBug() # The response page should have a bug number. self.assertIn('277761', response.body) # The anomaly entities should be updated. for anomaly_entity in anomaly.Anomaly.query().fetch(): if anomaly_entity.end_revision in [112005, 112010]: self.assertEqual(277761, anomaly_entity.bug_id) else: self.assertIsNone(anomaly_entity.bug_id) # Two HTTP requests are made when filing a bug; only test 2nd request. comment = self.service.add_comment_args[1] self.assertIn( 'https://chromeperf.appspot.com/group_report?bug_id=277761', comment) self.assertIn('https://chromeperf.appspot.com/group_report?keys=', comment) self.assertIn( '\n\n\nBot(s) for this bug\'s original alert(s):\n\nlinux', comment) @mock.patch.object(file_bug, '_GetAllCurrentVersionsFromOmahaProxy', mock.MagicMock(return_value=[{ 'versions': [{ 'branch_base_position': '112000', 'current_version': '2.0' }, { 'branch_base_position': '111990', 'current_version': '1.0' }] }])) @mock.patch.object(file_bug.auto_bisect, 'StartNewBisectForBug', mock.MagicMock(return_value={ 'issue_id': 123, 'issue_url': 'foo.com' })) def testGet_WithFinish_LabelsBugWithMilestone(self): # Here, we expect the bug to have the following start revisions: # [111995, 112005] and the milestones are M-1 for rev 111990 and # M-2 for 11200. Hence the expected behavior is to label the bug # M-2 since 111995 (lowest possible revision introducing regression) # is less than 112000 (revision for M-2). self._PostSampleBug() self.assertIn('M-2', self.service.new_bug_kwargs['labels']) @unittest.skip('Flaky; see #1555.') @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([{ 'versions': [{ 'branch_base_position': '111999', 'current_version': '3.0.1234.32' }, { 'branch_base_position': '112000', 'current_version': '2.0' }, { 'branch_base_position': '111990', 'current_version': '1.0' }] }])))) def testGet_WithFinish_LabelsBugWithLowestMilestonePossible(self): # Here, we expect the bug to have the following start revisions: # [111995, 112005] and the milestones are M-1 for rev 111990, M-2 # for 112000 and M-3 for 111999. Hence the expected behavior is to # label the bug M-2 since 111995 is less than 112000 (M-2) and 111999 # (M-3) AND M-2 is lower than M-3. self._PostSampleBug() self.assertIn('M-2', self.service.new_bug_kwargs['labels']) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock( return_value=testing_common.FakeResponseObject(200, '[]'))) def testGet_WithFinish_SucceedsWithNoVersions(self): # Here, we test that we don't label the bug with an unexpected value when # there is no version information from omahaproxy (for whatever reason) self._PostSampleBug() labels = self.service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock( return_value=testing_common.FakeResponseObject(200, '[]'))) def testGet_WithFinish_SucceedsWithComponents(self): # Here, we test that components are posted separately from labels. self._PostSampleBug() self.assertIn('Foo>Bar', self.service.new_bug_kwargs['components']) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([{ 'versions': [{ 'branch_base_position': '0', 'current_version': '1.0' }] }])))) def testGet_WithFinish_SucceedsWithRevisionOutOfRange(self): # Here, we test that we label the bug with the highest milestone when the # revision introducing regression is beyond all milestones in the list. self._PostSampleBug() self.assertIn('M-1', self.service.new_bug_kwargs['labels']) @mock.patch('google.appengine.api.urlfetch.fetch', mock.MagicMock(return_value=testing_common.FakeResponseObject( 200, json.dumps([{ 'versions': [{ 'branch_base_position': 'N/A', 'current_version': 'N/A' }] }])))) @mock.patch('logging.warn') def testGet_WithFinish_SucceedsWithNAAndLogsWarning(self, mock_warn): self._PostSampleBug() labels = self.service.new_bug_kwargs['labels'] self.assertEqual(0, len([x for x in labels if x.startswith(u'M-')])) self.assertEqual(1, mock_warn.call_count)
def _MockFailedFetch(url=None, deadline=None): del url del deadline return testing_common.FakeResponseObject(404, {})
def _GenerateResponse(self, build_details): encoded_build_data = base64.b64encode(json.dumps(build_details)) response_content = '12345%s' % json.dumps({'data': encoded_build_data}) return testing_common.FakeResponseObject(200, response_content)