blob: 13297af83256e71e444dd06796bc2e56c48291f7 [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 google.appengine.ext import ndb
from dashboard import auto_triage
from dashboard import issue_tracker_service
from dashboard import testing_common
from dashboard import utils
from dashboard.models import anomaly
from dashboard.models import bug_data
from dashboard.models import sheriff
@mock.patch('apiclient.discovery.build', mock.MagicMock())
@mock.patch.object(utils, 'ServiceAccountHttp', mock.MagicMock())
@mock.patch.object(utils, 'TickMonitoringCustomMetric', mock.MagicMock())
class AutoTriageTest(testing_common.TestCase):
def setUp(self):
super(AutoTriageTest, self).setUp()
app = webapp2.WSGIApplication(
[('/auto_triage', auto_triage.AutoTriageHandler)])
self.testapp = webtest.TestApp(app)
def _AddTestData(self, series, sheriff_key,
improvement_direction=anomaly.UP):
"""Adds one sample TestMetadata and associated data.
Args:
series: Either a list of values, or a list of (x, y) pairs.
sheriff_key: A Sheriff entity key.
improvement_direction: One of {anomaly.UP, anomaly.DOWN, anomaly.UNKNOWN}.
Returns:
The key of the TestMetadata entity that was added.
"""
testing_common.AddTests(['M'], ['b'], {'benchmark': {'t': {}}})
test_path = 'M/b/benchmark/t'
test = utils.TestKey(test_path).get()
test.improvement_direction = improvement_direction
test.sheriff = sheriff_key
sheriff_entity = sheriff_key.get()
sheriff_entity.patterns.append(test.test_path)
sheriff_entity.put()
if series and isinstance(series[0], (int, float)):
series = enumerate(series, start=1)
testing_common.AddRows(test_path, {x: {'value': y} for x, y in series})
return test.put()
def _AddAnomalyForTest(self, sheriff_key, test_key, revision,
median_before, median_after, bug_id=None):
"""Adds a sample Anomaly and returns the key."""
if bug_id > 0:
bug = ndb.Key('Bug', bug_id).get()
if not bug:
bug_data.Bug(id=bug_id).put()
return anomaly.Anomaly(
start_revision=revision,
end_revision=revision,
test=test_key,
median_before_anomaly=median_before,
median_after_anomaly=median_after,
bug_id=bug_id,
sheriff=sheriff_key).put()
def testPost_Recovered_MarkedAsRecovered(self):
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
values = [
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
55, 54, 55, 56, 54, 56, 57, 56, 55, 56,
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
]
test_key = self._AddTestData(values, sheriff_key)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=11, median_before=50, median_after=55)
self.testapp.post('/auto_triage')
self.assertTrue(anomaly_key.get().recovered)
def testPost_NotRecovered_NotMarkedAsRecovered(self):
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
values = [
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
55, 54, 55, 56, 54, 56, 57, 56, 55, 56,
55, 54, 55, 56, 54, 56, 57, 56, 55, 56,
]
test_key = self._AddTestData(values, sheriff_key)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=11, median_before=50, median_after=55)
self.testapp.post('/auto_triage')
self.assertFalse(anomaly_key.get().recovered)
def testPost_ChangeTooLarge_NotMarkedAsRecovered(self):
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
values = [
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
55, 54, 55, 56, 54, 56, 57, 56, 55, 56,
30, 29, 32, 34, 30, 31, 31, 32, 33, 30,
]
test_key = self._AddTestData(values, sheriff_key)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=11, median_before=50, median_after=55)
self.testapp.post('/auto_triage')
self.assertFalse(anomaly_key.get().recovered)
def testPost_ChangeWrongDirection_NotMarkedAsRecovered(self):
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
values = [
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
55, 54, 55, 56, 54, 56, 57, 56, 55, 56,
59, 60, 61, 60, 61, 59, 61, 60, 60, 59,
]
test_key = self._AddTestData(values, sheriff_key)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=11, median_before=50, median_after=55)
self.testapp.post('/auto_triage')
self.assertFalse(anomaly_key.get().recovered)
def testPost_AlertInvalid_NotMarkedAsRecovered(self):
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
values = [
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
55, 54, 55, 56, 54, 56, 57, 56, 55, 56,
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
]
test_key = self._AddTestData(values, sheriff_key)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=11, median_before=50, median_after=55,
bug_id=-1)
self.testapp.post('/auto_triage')
self.assertFalse(anomaly_key.get().recovered)
@mock.patch.object(
issue_tracker_service.IssueTrackerService, 'AddBugComment')
def testPost_AllAnomaliesRecovered_AddsComment(self, add_bug_comment_mock):
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
values = [
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
55, 54, 55, 56, 54, 56, 57, 56, 55, 56,
49, 50, 51, 50, 51, 49, 51, 50, 50, 49,
]
test_key = self._AddTestData(values, sheriff_key)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=11, median_before=50, median_after=55,
bug_id=1234)
self.testapp.post('/auto_triage')
self.ExecuteTaskQueueTasks('/auto_triage', auto_triage._TASK_QUEUE_NAME)
self.assertTrue(anomaly_key.get().recovered)
add_bug_comment_mock.assert_called_once_with(mock.ANY, mock.ANY)
@mock.patch.object(auto_triage.TriageBugs, '_CommentOnRecoveredBug')
def testPost_BugHasNoAlerts_NoCommentPosted(self, close_recovered_bug_mock):
bug_id = 1234
bug_data.Bug(id=bug_id).put()
self.testapp.post('/auto_triage')
self.ExecuteTaskQueueTasks('/auto_triage', auto_triage._TASK_QUEUE_NAME)
bug = ndb.Key('Bug', bug_id).get()
self.assertEqual(bug_data.BUG_STATUS_CLOSED, bug.status)
self.assertFalse(close_recovered_bug_mock.called)
def testPost_RealWorldExample_NoClearRecovery(self):
# This test is based on a real-world case on a relatively noisy graph where
# after the step up at r362262 the results meandered down again with no
# clear step. Alert key agxzfmNocm9tZXBlcmZyFAsSB0Fub21hbHkYgIDAnYnIqAoM.
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
series = [
(362080, 1562.6), (362086, 1641.4), (362095, 1572.4), (362102, 1552.9),
(362104, 1579.9), (362114, 1564.6), (362118, 1570.5), (362122, 1555.7),
(362129, 1550.1), (362134, 1547.5), (362149, 1536.2), (362186, 1533.1),
(362224, 1542.0), (362262, 1658.9), (362276, 1675.6), (362305, 1630.8),
(362321, 1664.7), (362345, 1659.6), (362361, 1669.4), (362366, 1681.6),
(362367, 1601.3), (362369, 1664.7), (362401, 1648.4), (362402, 1595.2),
(362417, 1676.9), (362445, 1532.0), (362470, 1631.9), (362490, 1585.1),
(362500, 1674.3), (362543, 1639.7), (362565, 1670.7), (362611, 1594.7),
(362635, 1677.5), (362638, 1687.5), (362650, 1702.2), (362663, 1614.9),
(362676, 1650.1), (362686, 1724.0), (362687, 1594.8), (362700, 1633.7),
(362721, 1684.1), (362744, 1678.7), (362776, 1642.4), (362899, 1591.1),
(362915, 1639.1), (362925, 1633.7), (362935, 1539.6), (362937, 1572.0),
(362950, 1567.4), (362963, 1608.3)
]
test_key = self._AddTestData(
series, sheriff_key, improvement_direction=anomaly.DOWN)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=362262,
median_before=1579.2, median_after=1680.7)
self.testapp.post('/auto_triage')
self.assertFalse(anomaly_key.get().recovered)
def testPost_RealisticExample_Recovered(self):
# This test is based on a real-world case where there was a step up at
# r362399, and shortly thereafter a step down at r362680 of roughly similar
# magnitude. Alert key agxzfmNocm9tZXBlcmZyFAsSB0Fub21hbHkYgIDAnbimogoM
sheriff_key = sheriff.Sheriff(email='a@google.com', id='sheriff_key').put()
series = [
(361776, 78260720), (361807, 78760907), (361837, 77723737),
(361864, 77984606), (361869, 78660955), (361879, 78276998),
(361903, 77420262), (362399, 79629598), (362416, 79631028),
(362428, 79074016), (362445, 79348860), (362483, 79724728),
(362532, 79673772), (362623, 79120915), (362641, 79384809),
(362666, 79885480), (362680, 78308585), (362701, 78063846),
(362730, 78244836), (362759, 77375408), (362799, 77836310),
(362908, 78069878), (362936, 77191699), (362958, 77951200),
(362975, 77906097)
]
test_key = self._AddTestData(
series, sheriff_key, improvement_direction=anomaly.DOWN)
anomaly_key = self._AddAnomalyForTest(
sheriff_key, test_key, revision=362399,
median_before=78275468.8, median_after=79630313.6)
self.testapp.post('/auto_triage')
self.assertTrue(anomaly_key.get().recovered)
if __name__ == '__main__':
unittest.main()