# Copyright 2015 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import unittest import mock import webapp2 import webtest # pylint: disable=unused-import from dashboard import mock_oauth2_decorator # pylint: enable=unused-import from dashboard import associate_alerts from dashboard import issue_tracker_service from dashboard import testing_common from dashboard import utils from dashboard.models import anomaly from dashboard.models import sheriff from dashboard.models import stoppage_alert class AssociateAlertsTest(testing_common.TestCase): def setUp(self): super(AssociateAlertsTest, self).setUp() app = webapp2.WSGIApplication([( '/associate_alerts', associate_alerts.AssociateAlertsHandler)]) self.testapp = webtest.TestApp(app) testing_common.SetSheriffDomains(['chromium.org']) self.SetCurrentUser('foo@chromium.org', is_admin=True) def _AddSheriff(self): """Adds a Sheriff and returns its key.""" return sheriff.Sheriff( id='Chromium Perf Sheriff', email='sullivan@google.com').put() def _AddTests(self): """Adds sample Tests and returns a list of their keys.""" testing_common.AddTests(['ChromiumGPU'], ['linux-release'], { 'scrolling-benchmark': { 'first_paint': {}, 'mean_frame_time': {}, } }) return map(utils.TestKey, [ 'ChromiumGPU/linux-release/scrolling-benchmark/first_paint', 'ChromiumGPU/linux-release/scrolling-benchmark/mean_frame_time', ]) def _AddAnomalies(self): """Adds sample Anomaly data and returns a dict of revision to key.""" sheriff_key = self._AddSheriff() test_keys = self._AddTests() key_map = {} # Add anomalies to the two tests alternately. for end_rev in range(10000, 10120, 10): test_key = test_keys[0] if end_rev % 20 == 0 else test_keys[1] anomaly_key = anomaly.Anomaly( start_revision=(end_rev - 5), end_revision=end_rev, test=test_key, median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key).put() key_map[end_rev] = anomaly_key.urlsafe() # Add an anomaly that overlaps. anomaly_key = anomaly.Anomaly( start_revision=9990, end_revision=9996, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key).put() key_map[9996] = anomaly_key.urlsafe() # Add an anomaly that overlaps and has bug ID. anomaly_key = anomaly.Anomaly( start_revision=9990, end_revision=9997, test=test_keys[0], median_before_anomaly=100, median_after_anomaly=200, sheriff=sheriff_key, bug_id=12345).put() key_map[9997] = anomaly_key.urlsafe() return key_map def testGet_NoKeys_ShowsError(self): response = self.testapp.get('/associate_alerts') self.assertIn('
', response.body) def testGet_SameAsPost(self): get_response = self.testapp.get('/associate_alerts') post_response = self.testapp.post('/associate_alerts') self.assertEqual(get_response.body, post_response.body) def testGet_InvalidBugId_ShowsError(self): key_map = self._AddAnomalies() response = self.testapp.get( '/associate_alerts?keys=%s&bug_id=foo' % key_map[9996]) self.assertIn('
', response.body) self.assertIn('Invalid bug ID', response.body) # Mocks fetching bugs from issue tracker. @mock.patch('issue_tracker_service.discovery.build', mock.MagicMock()) @mock.patch.object( issue_tracker_service.IssueTrackerService, 'List', mock.MagicMock(return_value={ 'items': [ { 'id': 12345, 'summary': '5% regression in bot/suite/x at 10000:20000', 'state': 'open', 'status': 'New', 'author': {'name': 'exam...@google.com'}, }, { 'id': 13579, 'summary': '1% regression in bot/suite/y at 10000:20000', 'state': 'closed', 'status': 'WontFix', 'author': {'name': 'exam...@google.com'}, }, ]})) def testGet_NoBugId_ShowsDialog(self): # When a GET request is made with some anomaly keys but no bug ID, # A HTML form is shown for the user to input a bug number. key_map = self._AddAnomalies() response = self.testapp.get('/associate_alerts?keys=%s' % key_map[10000]) # The response contains a table of recent bugs and a form. self.assertIn('12345', response.body) self.assertIn('13579', response.body) self.assertIn('