blob: c89469a9ab7e3d2b5708fee8e586227b10dbaf77 [file] [log] [blame]
# 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
from dashboard import alerts
from dashboard import testing_common
from dashboard import utils
from dashboard.models import anomaly
from dashboard.models import bug_data
from dashboard.models import graph_data
from dashboard.models import sheriff
from dashboard.models import stoppage_alert
class AlertsTest(testing_common.TestCase):
# TODO(qyearsley): Simplify this unit test.
def setUp(self):
super(AlertsTest, self).setUp()
app = webapp2.WSGIApplication([('/alerts', alerts.AlertsHandler)])
self.testapp = webtest.TestApp(app)
def _AddAlertsToDataStore(self):
"""Adds sample data, including triaged and non-triaged alerts."""
key_map = {}
sheriff_key = sheriff.Sheriff(
id='Chromium Perf Sheriff', email='sullivan@google.com').put()
testing_common.AddTests(['ChromiumGPU'], ['linux-release'], {
'scrolling-benchmark': {
'first_paint': {},
'mean_frame_time': {},
}
})
first_paint = utils.TestKey(
'ChromiumGPU/linux-release/scrolling-benchmark/first_paint')
mean_frame_time = utils.TestKey(
'ChromiumGPU/linux-release/scrolling-benchmark/mean_frame_time')
# By default, all Test entities have an improvement_direction of UNKNOWN,
# meaning that neither direction is considered an improvement.
# Here we set the improvement direction so that some anomalies are
# considered improvements.
for test_key in [first_paint, mean_frame_time]:
test = test_key.get()
test.improvement_direction = anomaly.DOWN
test.put()
# Add some (12) non-triaged alerts.
for end_rev in range(10000, 10120, 10):
test_key = first_paint if end_rev % 20 == 0 else mean_frame_time
anomaly_entity = 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)
anomaly_entity.SetIsImprovement()
anomaly_key = anomaly_entity.put()
key_map[end_rev] = anomaly_key.urlsafe()
# Add some (2) already-triaged alerts.
for end_rev in range(10120, 10140, 10):
test_key = first_paint if end_rev % 20 == 0 else mean_frame_time
bug_id = -1 if end_rev % 20 == 0 else 12345
anomaly_entity = anomaly.Anomaly(
start_revision=end_rev - 5, end_revision=end_rev, test=test_key,
median_before_anomaly=100, median_after_anomaly=200,
bug_id=bug_id, sheriff=sheriff_key)
anomaly_entity.SetIsImprovement()
anomaly_key = anomaly_entity.put()
key_map[end_rev] = anomaly_key.urlsafe()
if bug_id > 0:
bug_data.Bug(id=bug_id).put()
# Add some (6) non-triaged improvements.
for end_rev in range(10140, 10200, 10):
test_key = mean_frame_time
anomaly_entity = anomaly.Anomaly(
start_revision=end_rev - 5, end_revision=end_rev, test=test_key,
median_before_anomaly=200, median_after_anomaly=100,
sheriff=sheriff_key)
anomaly_entity.SetIsImprovement()
anomaly_key = anomaly_entity.put()
self.assertTrue(anomaly_entity.is_improvement)
key_map[end_rev] = anomaly_key.urlsafe()
return key_map
def testGet(self):
response = self.testapp.get('/alerts')
self.assertEqual('text/html', response.content_type)
self.assertIn('Chrome Performance Alerts', response.body)
def testPost_NoParametersSet_UntriagedAlertsListed(self):
key_map = self._AddAlertsToDataStore()
response = self.testapp.post('/alerts')
anomaly_list = self.GetJsonValue(response, 'anomaly_list')
self.assertEqual(12, len(anomaly_list))
# The test below depends on the order of the items, but the order is not
# guaranteed; it depends on the timestamps, which depend on put order.
anomaly_list.sort(key=lambda a: -a['end_revision'])
expected_end_rev = 10110
for alert in anomaly_list:
self.assertEqual(expected_end_rev, alert['end_revision'])
self.assertEqual(expected_end_rev - 5, alert['start_revision'])
self.assertEqual(key_map[expected_end_rev], alert['key'])
self.assertEqual('ChromiumGPU', alert['master'])
self.assertEqual('linux-release', alert['bot'])
self.assertEqual('scrolling-benchmark', alert['testsuite'])
if expected_end_rev % 20 == 0:
self.assertEqual('first_paint', alert['test'])
else:
self.assertEqual('mean_frame_time', alert['test'])
self.assertEqual('100.0%', alert['percent_changed'])
self.assertIsNone(alert['bug_id'])
expected_end_rev -= 10
self.assertEqual(expected_end_rev, 9990)
def testPost_TriagedParameterSet_TriagedListed(self):
self._AddAlertsToDataStore()
response = self.testapp.post('/alerts', {'triaged': 'true'})
anomaly_list = self.GetJsonValue(response, 'anomaly_list')
# The alerts listed should contain those added above, including alerts
# that have a bug ID that is not None.
self.assertEqual(14, len(anomaly_list))
expected_end_rev = 10130
# The test below depends on the order of the items, but the order is not
# guaranteed; it depends on the timestamps, which depend on put order.
anomaly_list.sort(key=lambda a: -a['end_revision'])
for alert in anomaly_list:
if expected_end_rev == 10130:
self.assertEqual(12345, alert['bug_id'])
elif expected_end_rev == 10120:
self.assertEqual(-1, alert['bug_id'])
else:
self.assertIsNone(alert['bug_id'])
expected_end_rev -= 10
self.assertEqual(expected_end_rev, 9990)
def testPost_ImprovementsParameterSet_ListsImprovements(self):
self._AddAlertsToDataStore()
response = self.testapp.post('/alerts', {'improvements': 'true'})
anomaly_list = self.GetJsonValue(response, 'anomaly_list')
self.assertEqual(18, len(anomaly_list))
def testPost_SheriffParameterSet_OtherSheriffAlertsListed(self):
self._AddAlertsToDataStore()
# Add another sheriff to the mock datastore, and set the sheriff of some
# anomalies to be this new sheriff.
sheriff2_key = sheriff.Sheriff(
id='Sheriff2', email='sullivan@google.com').put()
mean_frame_time = utils.TestKey(
'ChromiumGPU/linux-release/scrolling-benchmark/mean_frame_time')
anomalies = anomaly.Anomaly.query(
anomaly.Anomaly.test == mean_frame_time).fetch()
for anomaly_entity in anomalies:
anomaly_entity.sheriff = sheriff2_key
anomaly_entity.put()
response = self.testapp.post('/alerts', {'sheriff': 'Sheriff2'})
anomaly_list = self.GetJsonValue(response, 'anomaly_list')
sheriff_list = self.GetJsonValue(response, 'sheriff_list')
for alert in anomaly_list:
self.assertEqual('mean_frame_time', alert['test'])
self.assertEqual(2, len(sheriff_list))
self.assertEqual('Chromium Perf Sheriff', sheriff_list[0])
self.assertEqual('Sheriff2', sheriff_list[1])
def testPost_StoppageAlerts_EmbedsStoppageAlertListAndOneTable(self):
sheriff.Sheriff(id='Sheriff', patterns=['M/b/*/*']).put()
testing_common.AddTests(['M'], ['b'], {'foo': {'bar': {}}})
test_key = utils.TestKey('M/b/foo/bar')
rows = testing_common.AddRows('M/b/foo/bar', {9800, 9802})
for row in rows:
stoppage_alert.CreateStoppageAlert(test_key.get(), row).put()
response = self.testapp.post('/alerts?sheriff=Sheriff')
stoppage_alert_list = self.GetJsonValue(response, 'stoppage_alert_list')
self.assertEqual(2, len(stoppage_alert_list))
@mock.patch('logging.error')
def testPost_StoppageAlertWithBogusRow_LogsErrorAndShowsTable(
self, mock_logging_error):
sheriff.Sheriff(id='Sheriff', patterns=['M/b/*/*']).put()
testing_common.AddTests(['M'], ['b'], {'foo': {'bar': {}}})
test_key = utils.TestKey('M/b/foo/bar')
row_parent = utils.GetTestContainerKey(test_key)
row = graph_data.Row(parent=row_parent, id=1234)
stoppage_alert.CreateStoppageAlert(test_key.get(), row).put()
response = self.testapp.post('/alerts?sheriff=Sheriff')
stoppage_alert_list = self.GetJsonValue(response, 'stoppage_alert_list')
self.assertEqual(1, len(stoppage_alert_list))
self.assertEqual(1, mock_logging_error.call_count)
def testPost_WithBogusSheriff_HasErrorMessage(self):
response = self.testapp.post('/alerts?sheriff=Foo')
error = self.GetJsonValue(response, 'error')
self.assertIsNotNone(error)
def testPost_ExternalUserRequestsInternalOnlySheriff_ErrorMessage(self):
sheriff.Sheriff(id='Foo', internal_only=True).put()
self.assertFalse(utils.IsInternalUser())
response = self.testapp.post('/alerts?sheriff=Foo')
error = self.GetJsonValue(response, 'error')
self.assertIsNotNone(error)
if __name__ == '__main__':
unittest.main()