blob: 167fa700283bde83d38b65a1651eb0c7a6371aa2 [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.
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import sys
import unittest
import mock
from google.appengine.ext import ndb
from dashboard import find_anomalies
from dashboard import find_change_points
from dashboard.common import testing_common
from dashboard.common import utils
from dashboard.models import alert_group
from dashboard.models import anomaly
from dashboard.models import anomaly_config
from dashboard.models import graph_data
from dashboard.models import histogram
from dashboard.models.subscription import Subscription
from dashboard.models.subscription import VISIBILITY
from tracing.value.diagnostics import reserved_infos
from dashboard.sheriff_config_client import SheriffConfigClient
# pylint: disable=too-many-lines
# Sample time series.
_TEST_ROW_DATA = [
(241105, 2136.7),
(241116, 2140.3),
(241151, 2149.1),
(241154, 2147.2),
(241156, 2130.6),
(241160, 2136.2),
(241188, 2146.7),
(241201, 2141.8),
(241226, 2140.6),
(241247, 2128.1),
(241249, 2134.2),
(241254, 2130.0),
(241262, 2136.0),
(241268, 2142.6),
(241271, 2149.1),
(241282, 2156.6),
(241294, 2125.3),
(241298, 2155.5),
(241303, 2148.5),
(241317, 2146.2),
(241323, 2123.3),
(241330, 2121.5),
(241342, 2141.2),
(241355, 2145.2),
(241371, 2136.3),
(241386, 2144.0),
(241405, 2138.1),
(241420, 2147.6),
(241432, 2140.7),
(241441, 2132.2),
(241452, 2138.2),
(241455, 2139.3),
(241471, 2134.0),
(241488, 2137.2),
(241503, 2152.5),
(241520, 2136.3),
(241524, 2139.3),
(241529, 2143.5),
(241532, 2145.5),
(241535, 2147.0),
(241537, 2184.1),
(241546, 2180.8),
(241553, 2181.5),
(241559, 2176.8),
(241566, 2174.0),
(241577, 2182.8),
(241579, 2184.8),
(241582, 2190.5),
(241584, 2183.1),
(241609, 2178.3),
(241620, 2178.1),
(241645, 2190.8),
(241653, 2177.7),
(241666, 2185.3),
(241697, 2173.8),
(241716, 2172.1),
(241735, 2172.5),
(241757, 2174.7),
(241766, 2196.7),
(241782, 2184.1),
]
def _MakeSampleChangePoint(x_value, median_before, median_after):
"""Makes a sample find_change_points.ChangePoint for use in these tests."""
# The only thing that matters in these tests is the revision number
# and the values before and after.
return find_change_points.ChangePoint(
x_value=x_value,
median_before=median_before,
median_after=median_after,
window_start=1,
window_end=8,
size_before=None,
size_after=None,
relative_change=None,
std_dev_before=None,
t_statistic=None,
degrees_of_freedom=None,
p_value=None,
extended_start=x_value,
extended_end=x_value,
)
class EndRevisionMatcher(object):
"""Custom matcher to test if an anomaly matches a given end rev."""
def __init__(self, end_revision):
"""Initializes with the end time to check."""
self._end_revision = end_revision
def __eq__(self, rhs):
"""Checks to see if RHS has the same end time."""
return self._end_revision == rhs.end_revision
def __repr__(self):
"""Shows a readable revision which can be printed when assert fails."""
return '<IsEndRevision %d>' % self._end_revision
class ModelMatcher(object):
"""Custom matcher to check if two ndb entity names match."""
def __init__(self, name):
"""Initializes with the name of the entity."""
self._name = name
def __eq__(self, rhs):
"""Checks to see if RHS has the same name."""
return (rhs.key.string_id() if rhs.key else rhs.name) == self._name
def __repr__(self):
"""Shows a readable revision which can be printed when assert fails."""
return '<IsModel %s>' % self._name
@ndb.tasklet
def _MockTasklet(*_):
raise ndb.Return(None)
@mock.patch.object(SheriffConfigClient, '__init__',
mock.MagicMock(return_value=None))
class ProcessAlertsTest(testing_common.TestCase):
def setUp(self):
super(ProcessAlertsTest, self).setUp()
self.SetCurrentUser('foo@bar.com', is_admin=True)
def _AddDataForTests(self, stats=None, masters=None):
if not masters:
masters = ['ChromiumGPU']
testing_common.AddTests(masters, ['linux-release'], {
'scrolling_benchmark': {
'ref': {},
},
})
for m in masters:
ref = utils.TestKey('%s/linux-release/scrolling_benchmark/ref' % m).get()
ref.units = 'ms'
for i in range(9000, 10070, 5):
# Internal-only data should be found.
test_container_key = utils.GetTestContainerKey(ref.key)
r = graph_data.Row(
id=i + 1,
value=float(i * 3),
parent=test_container_key,
internal_only=True)
if stats:
for s in stats:
setattr(r, s, i)
r.put()
def _DataSeries(self):
return [(r.revision, r, r.value) for r in list(graph_data.Row.query())]
@mock.patch.object(find_anomalies.find_change_points, 'FindChangePoints',
mock.MagicMock(return_value=[
_MakeSampleChangePoint(10011, 50, 100),
_MakeSampleChangePoint(10041, 200, 100),
_MakeSampleChangePoint(10061, 0, 100),
]))
@mock.patch.object(find_anomalies.email_sheriff, 'EmailSheriff')
def testProcessTest(self, mock_email_sheriff):
self._AddDataForTests()
test_path = 'ChromiumGPU/linux-release/scrolling_benchmark/ref'
test = utils.TestKey(test_path).get()
test.UpdateSheriff()
test.put()
alert_group_key1 = alert_group.AlertGroup(
name='scrolling_benchmark',
subscription_name='sheriff1',
status=alert_group.AlertGroup.Status.untriaged,
active=True,
revision=alert_group.RevisionRange(
repository='chromium', start=10000, end=10070),
).put()
alert_group_key2 = alert_group.AlertGroup(
name='scrolling_benchmark',
subscription_name='sheriff2',
status=alert_group.AlertGroup.Status.untriaged,
active=True,
revision=alert_group.RevisionRange(
repository='chromium', start=10000, end=10070),
).put()
s1 = Subscription(name='sheriff1', visibility=VISIBILITY.PUBLIC)
s2 = Subscription(name='sheriff2', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s1, s2], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.key.id())])
self.ExecuteDeferredTasks('default')
expected_calls = [
mock.call(
[ModelMatcher('sheriff1'),
ModelMatcher('sheriff2')],
ModelMatcher('ChromiumGPU/linux-release/scrolling_benchmark/ref'),
EndRevisionMatcher(10011)),
mock.call(
[ModelMatcher('sheriff1'),
ModelMatcher('sheriff2')],
ModelMatcher('ChromiumGPU/linux-release/scrolling_benchmark/ref'),
EndRevisionMatcher(10041)),
mock.call(
[ModelMatcher('sheriff1'),
ModelMatcher('sheriff2')],
ModelMatcher('ChromiumGPU/linux-release/scrolling_benchmark/ref'),
EndRevisionMatcher(10061))
]
self.assertEqual(expected_calls, mock_email_sheriff.call_args_list)
anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(len(anomalies), 3)
for a in anomalies:
self.assertEqual(a.groups, [alert_group_key1, alert_group_key2])
def AnomalyExists(anomalies, test, percent_changed, direction,
start_revision, end_revision, subscription_names,
internal_only, units, absolute_delta, statistic):
for a in anomalies:
if (a.test == test and a.percent_changed == percent_changed
and a.direction == direction and a.start_revision == start_revision
and a.end_revision == end_revision
and a.subscription_names == subscription_names
and a.internal_only == internal_only and a.units == units
and a.absolute_delta == absolute_delta
and a.statistic == statistic):
return True
return False
self.assertTrue(
AnomalyExists(
anomalies,
test.key,
percent_changed=100,
direction=anomaly.UP,
start_revision=10007,
end_revision=10011,
subscription_names=['sheriff1', 'sheriff2'],
internal_only=False,
units='ms',
absolute_delta=50,
statistic='avg'))
self.assertTrue(
AnomalyExists(
anomalies,
test.key,
percent_changed=-50,
direction=anomaly.DOWN,
start_revision=10037,
end_revision=10041,
subscription_names=['sheriff1', 'sheriff2'],
internal_only=False,
units='ms',
absolute_delta=-100,
statistic='avg'))
self.assertTrue(
AnomalyExists(
anomalies,
test.key,
percent_changed=sys.float_info.max,
direction=anomaly.UP,
start_revision=10057,
end_revision=10061,
internal_only=False,
units='ms',
subscription_names=['sheriff1', 'sheriff2'],
absolute_delta=100,
statistic='avg'))
# This is here just to verify that AnomalyExists returns False sometimes.
self.assertFalse(
AnomalyExists(
anomalies,
test.key,
percent_changed=100,
direction=anomaly.DOWN,
start_revision=10037,
end_revision=10041,
subscription_names=['sheriff1', 'sheriff2'],
internal_only=False,
units='ms',
absolute_delta=500,
statistic='avg'))
@mock.patch.object(find_anomalies, '_ProcessTestStat')
def testProcessTest_SkipsClankInternal(self, mock_process_stat):
mock_process_stat.side_effect = _MockTasklet
self._AddDataForTests(masters=['ClankInternal'])
test_path = 'ClankInternal/linux-release/scrolling_benchmark/ref'
test = utils.TestKey(test_path).get()
a = anomaly.Anomaly(
test=test.key,
start_revision=10061,
end_revision=10062,
statistic='avg')
a.put()
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [])
self.ExecuteDeferredTasks('default')
self.assertFalse(mock_process_stat.called)
@mock.patch.object(find_anomalies, '_ProcessTestStat')
def testProcessTest_UsesLastAlert_Avg(self, mock_process_stat):
mock_process_stat.side_effect = _MockTasklet
self._AddDataForTests()
test_path = 'ChromiumGPU/linux-release/scrolling_benchmark/ref'
test = utils.TestKey(test_path).get()
a = anomaly.Anomaly(
test=test.key,
start_revision=10061,
end_revision=10062,
statistic='avg')
a.put()
test.UpdateSheriff()
test.put()
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([], None))):
find_anomalies.ProcessTests([test.key])
self.ExecuteDeferredTasks('default')
query = graph_data.Row.query(projection=['revision', 'timestamp', 'value'])
query = query.filter(graph_data.Row.revision > 10062)
query = query.filter(
graph_data.Row.parent_test == utils.OldStyleTestKey(test.key))
row_data = query.fetch()
rows = [(r.revision, r, r.value) for r in row_data]
mock_process_stat.assert_called_with(mock.ANY, mock.ANY, mock.ANY, rows,
None)
anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(len(anomalies), 1)
@mock.patch.object(find_anomalies, '_ProcessTestStat')
def testProcessTest_SkipsLastAlert_NotAvg(self, mock_process_stat):
self._AddDataForTests(stats=('count',))
test_path = 'ChromiumGPU/linux-release/scrolling_benchmark/ref'
test = utils.TestKey(test_path).get()
a = anomaly.Anomaly(
test=test.key,
start_revision=10061,
end_revision=10062,
statistic='count')
a.put()
test.UpdateSheriff()
test.put()
@ndb.tasklet
def _AssertParams(config, test_entity, stat, rows, ref_rows):
del config
del test_entity
del stat
del ref_rows
assert rows[0][0] < a.end_revision
mock_process_stat.side_effect = _AssertParams
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([], None))):
find_anomalies.ProcessTests([test.key])
self.ExecuteDeferredTasks('default')
@mock.patch.object(
find_anomalies.find_change_points, 'FindChangePoints',
mock.MagicMock(return_value=[_MakeSampleChangePoint(10011, 100, 50)]))
def testProcessTest_ImprovementMarkedAsImprovement(self):
self._AddDataForTests()
test = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
test.improvement_direction = anomaly.DOWN
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.key.id())])
anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(len(anomalies), 1)
self.assertTrue(anomalies[0].is_improvement)
@mock.patch('logging.error')
def testProcessTest_NoSheriff_ErrorLogged(self, mock_logging_error):
self._AddDataForTests()
ref = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([], None))):
find_anomalies.ProcessTests([ref.key])
mock_logging_error.assert_called_with('No subscription for %s',
ref.key.string_id())
@mock.patch.object(find_anomalies.find_change_points, 'FindChangePoints',
mock.MagicMock(return_value=[
_MakeSampleChangePoint(10026, 55.2, 57.8),
_MakeSampleChangePoint(10041, 45.2, 37.8),
]))
@mock.patch.object(find_anomalies.email_sheriff, 'EmailSheriff')
def testProcessTest_FiltersOutImprovements(self, mock_email_sheriff):
self._AddDataForTests()
test = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
test.improvement_direction = anomaly.UP
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.key.id())])
self.ExecuteDeferredTasks('default')
mock_email_sheriff.assert_called_once_with(
[ModelMatcher('sheriff')],
ModelMatcher('ChromiumGPU/linux-release/scrolling_benchmark/ref'),
EndRevisionMatcher(10041))
@mock.patch.object(find_anomalies.find_change_points, 'FindChangePoints',
mock.MagicMock(return_value=[
_MakeSampleChangePoint(10011, 50, 100),
]))
@mock.patch.object(find_anomalies.email_sheriff, 'EmailSheriff')
def testProcessTest_InternalOnlyTest(self, mock_email_sheriff):
self._AddDataForTests()
test = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
test.internal_only = True
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.key.id())])
self.ExecuteDeferredTasks('default')
expected_calls = [
mock.call(
[ModelMatcher('sheriff')],
ModelMatcher('ChromiumGPU/linux-release/scrolling_benchmark/ref'),
EndRevisionMatcher(10011))
]
self.assertEqual(expected_calls, mock_email_sheriff.call_args_list)
anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(len(anomalies), 1)
self.assertEqual(test.key, anomalies[0].test)
self.assertEqual(100, anomalies[0].percent_changed)
self.assertEqual(anomaly.UP, anomalies[0].direction)
self.assertEqual(10007, anomalies[0].start_revision)
self.assertEqual(10011, anomalies[0].end_revision)
self.assertTrue(anomalies[0].internal_only)
def testProcessTest_CreatesAnAnomaly_RefMovesToo_BenchmarkDuration(self):
testing_common.AddTests(['ChromiumGPU'], ['linux-release'], {
'foo': {
'benchmark_duration': {
'ref': {}
}
},
})
ref = utils.TestKey(
'ChromiumGPU/linux-release/foo/benchmark_duration/ref').get()
non_ref = utils.TestKey(
'ChromiumGPU/linux-release/foo/benchmark_duration').get()
test_container_key = utils.GetTestContainerKey(ref.key)
test_container_key_non_ref = utils.GetTestContainerKey(non_ref.key)
for row in _TEST_ROW_DATA:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
graph_data.Row(
id=row[0], value=row[1], parent=test_container_key_non_ref).put()
ref.UpdateSheriff()
ref.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([ref.key])
self.assertEqual(m.call_args_list, [mock.call(ref.key.id())])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(1, len(new_anomalies))
def testProcessTest_AnomaliesMatchRefSeries_NoAlertCreated(self):
# Tests that a Anomaly entity is not created if both the test and its
# corresponding ref build series have the same data.
testing_common.AddTests(['ChromiumGPU'], ['linux-release'], {
'scrolling_benchmark': {
'ref': {}
},
})
ref = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
non_ref = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark').get()
test_container_key = utils.GetTestContainerKey(ref.key)
test_container_key_non_ref = utils.GetTestContainerKey(non_ref.key)
for row in _TEST_ROW_DATA:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
graph_data.Row(
id=row[0], value=row[1], parent=test_container_key_non_ref).put()
ref.UpdateSheriff()
ref.put()
non_ref.UpdateSheriff()
non_ref.put()
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([], None))):
find_anomalies.ProcessTests([non_ref.key])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(0, len(new_anomalies))
def testProcessTest_AnomalyDoesNotMatchRefSeries_AlertCreated(self):
# Tests that an Anomaly entity is created when non-ref series goes up, but
# the ref series stays flat.
testing_common.AddTests(['ChromiumGPU'], ['linux-release'], {
'scrolling_benchmark': {
'ref': {}
},
})
ref = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
non_ref = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark').get()
test_container_key = utils.GetTestContainerKey(ref.key)
test_container_key_non_ref = utils.GetTestContainerKey(non_ref.key)
for row in _TEST_ROW_DATA:
graph_data.Row(id=row[0], value=2125.375, parent=test_container_key).put()
graph_data.Row(
id=row[0], value=row[1], parent=test_container_key_non_ref).put()
ref.UpdateSheriff()
ref.put()
non_ref.UpdateSheriff()
non_ref.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([non_ref.key])
self.assertEqual(m.call_args_list, [mock.call(non_ref.key.id())])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(len(new_anomalies), 1)
def testProcessTest_CreatesAnAnomaly(self):
testing_common.AddTests(['ChromiumGPU'], ['linux-release'], {
'scrolling_benchmark': {
'ref': {}
},
})
ref = utils.TestKey(
'ChromiumGPU/linux-release/scrolling_benchmark/ref').get()
test_container_key = utils.GetTestContainerKey(ref.key)
for row in _TEST_ROW_DATA:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
ref.UpdateSheriff()
ref.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([ref.key])
self.assertEqual(m.call_args_list, [mock.call(ref.key.id())])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(1, len(new_anomalies))
self.assertEqual(anomaly.UP, new_anomalies[0].direction)
self.assertEqual(241533, new_anomalies[0].start_revision)
self.assertEqual(241546, new_anomalies[0].end_revision)
def testProcessTest_RefineAnomalyPlacement_OffByOneBefore(self):
testing_common.AddTests(
['ChromiumPerf'], ['linux-perf'],
{'blink_perf.layout': {
'nested-percent-height-tables': {}
}})
test = utils.TestKey(
'ChromiumPerf/linux-perf/blink_perf.layout/nested-percent-height-tables'
).get()
test_container_key = utils.GetTestContainerKey(test.key)
sample_data = [
(728446, 480.2504),
(728462, 487.685),
(728469, 486.6389),
(728480, 477.6597),
(728492, 471.2238),
(728512, 480.4379),
(728539, 464.5573),
(728594, 489.0594),
(728644, 484.4796),
(728714, 489.5986),
(728751, 489.474),
(728788, 481.9336),
(728835, 484.089),
(728869, 485.4287),
(728883, 476.8234),
(728907, 487.4736),
(728938, 490.601),
(728986, 483.5039),
(729021, 485.176),
(729066, 484.5855),
(729105, 483.9114),
(729119, 483.559),
(729161, 477.6875),
(729201, 484.9668),
(729240, 480.7091),
(729270, 484.5506),
(729292, 495.1445),
(729309, 479.9111),
(729329, 479.8815),
(729391, 487.5683),
(729430, 476.7355),
(729478, 487.7251),
(729525, 493.1012),
(729568, 497.7565),
(729608, 499.6481),
(729642, 496.1591),
(729658, 493.4581),
(729687, 486.1097),
(729706, 478.036),
(729730, 480.4222), # In crbug/1041688 this was the original placement.
(729764, 421.0342), # We instead should be setting it here.
(729795, 428.0284),
(729846, 433.8261),
(729883, 429.49),
(729920, 436.3342),
(729975, 434.3996),
(730011, 428.3672),
(730054, 436.309),
(730094, 435.3792),
(730128, 433.0537),
]
for row in sample_data:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.test_path)])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(1, len(new_anomalies))
self.assertEqual(anomaly.DOWN, new_anomalies[0].direction)
self.assertEqual(729731, new_anomalies[0].start_revision)
self.assertEqual(729764, new_anomalies[0].end_revision)
def testProcessTest_RefineAnomalyPlacement_OffByOneStable(self):
testing_common.AddTests(
['ChromiumPerf'], ['linux-perf'], {
'memory.desktop': {
('memory:chrome:all_processes:'
'reported_by_chrome:v8:effective_size_avg'): {}
}
})
test = utils.TestKey(
('ChromiumPerf/linux-perf/memory.desktop/'
'memory:chrome:all_processes:reported_by_chrome:v8:effective_size_avg'
)).get()
test_container_key = utils.GetTestContainerKey(test.key)
sample_data = [
(733480, 1381203.0),
(733494, 1381220.0),
(733504, 1381212.0),
(733524, 1381220.0),
(733538, 1381211.0),
(733544, 1381212.0),
(733549, 1381220.0),
(733563, 1381220.0),
(733581, 1381220.0),
(733597, 1381212.0),
(733611, 1381228.0),
(733641, 1381212.0),
(733675, 1381204.0),
(733721, 1381212.0),
(733766, 1381211.0),
(733804, 1381204.0),
(733835, 1381219.0),
(733865, 1381211.0),
(733885, 1381219.0),
(733908, 1381204.0),
(733920, 1381211.0),
(733937, 1381220.0),
(734091, 1381211.0),
(734133, 1381219.0),
(734181, 1381204.0),
(734211, 1381720.0),
(734248, 1381712.0),
(734277, 1381696.0),
(734311, 1381704.0),
(734341, 1381703.0),
(734372, 1381704.0),
(734405, 1381703.0),
(734431, 1381711.0),
(734456, 1381720.0),
(734487, 1381703.0),
(734521, 1381704.0),
(734554, 1381726.0),
(734598, 1381704.0),
(734630, 1381703.0), # In crbug/1041688 this is where it was placed.
(734673, 1529888.0), # This is where it should be.
(734705, 1529888.0),
(734739, 1529860.0),
(734770, 1529860.0),
(734793, 1529888.0),
(734829, 1529860.0),
]
for row in sample_data:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.test_path)])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(1, len(new_anomalies))
self.assertEqual(anomaly.UP, new_anomalies[0].direction)
self.assertEqual(734631, new_anomalies[0].start_revision)
self.assertEqual(734673, new_anomalies[0].end_revision)
def testProcessTest_RefineAnomalyPlacement_MinSize0Max2Elements(self):
testing_common.AddTests(['ChromiumPerf'], ['linux-perf'],
{'sizes': {
'method_count': {}
}})
test = utils.TestKey(('ChromiumPerf/linux-perf/sizes/method_count')).get()
test_container_key = utils.GetTestContainerKey(test.key)
custom_config = {
'max_window_size': 10,
'min_absolute_change': 50,
'min_relative_change': 0,
'min_segment_size': 0,
}
anomaly_config.AnomalyConfig(
config=custom_config, patterns=[test.test_path]).put()
test.UpdateSheriff()
test.put()
self.assertEqual(custom_config, anomaly_config.GetAnomalyConfigDict(test))
sample_data = [
(6990, 100),
(6991, 100),
(6992, 100),
(6993, 100),
(6994, 100),
(6995, 100),
(6996, 100),
(6997, 100),
(6998, 100),
(6999, 100),
(7000, 100),
(7001, 155),
(7002, 155),
(7003, 155),
]
for row in sample_data:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.test_path)])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(1, len(new_anomalies))
self.assertEqual(anomaly.UP, new_anomalies[0].direction)
self.assertEqual(7001, new_anomalies[0].start_revision)
self.assertEqual(7001, new_anomalies[0].end_revision)
def testProcessTest_MultipleChangePoints(self):
testing_common.AddTests(
['ChromiumPerf'], ['linux-perf'],
{'blink_perf.layout': {
'nested-percent-height-tables': {}
}})
test = utils.TestKey(
'ChromiumPerf/linux-perf/blink_perf.layout/nested-percent-height-tables'
).get()
test_container_key = utils.GetTestContainerKey(test.key)
sample_data = [
(804863, 13830765),
(804867, 16667862),
(804879, 13929296),
(804891, 13823876),
(804896, 13908794),
(804900, 13899281),
(804907, 14901462),
(804921, 13890597),
(804935, 13969113),
(804946, 13996520),
(804957, 13913104),
(805143, 16770364),
(805175, 14858529),
(805179, 14013942),
(805185, 14857516),
(805195, 14895168),
(805196, 14944037),
(805205, 13919484),
(805211, 15736581),
(805231, 14730142),
(805236, 13892102),
(805247, 14808876),
(805253, 14903648),
(805262, 13896626),
(805276, 15797878),
(805281, 14542593),
(805285, 15733168),
(805290, 13882841),
(805302, 15727394),
(805314, 15758058),
(805333, 16074960),
(805345, 16142162),
(805359, 16138912),
(805384, 17914289),
(805412, 18368834),
(805428, 18055197),
(805457, 19673614),
(805482, 19705606),
(805502, 19609089),
(805509, 19576745),
(805531, 19600059),
(805550, 19702969),
(805564, 19660953),
(805584, 19830273),
(805600, 19800662),
(805606, 19493150),
(805620, 19700545),
(805624, 19623731),
(805628, 19683921),
(805634, 19660001),
]
for row in sample_data:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.test_path)])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(2, len(new_anomalies))
self.assertEqual(anomaly.UP, new_anomalies[0].direction)
self.assertEqual(805429, new_anomalies[0].start_revision)
self.assertEqual(805457, new_anomalies[0].end_revision)
self.assertEqual(805315, new_anomalies[1].start_revision)
self.assertEqual(805428, new_anomalies[1].end_revision)
def testProcessTest__RefineAnomalyPlacement_BalancedEstimator1(self):
testing_common.AddTests(
['ChromiumPerf'], ['linux-perf'],
{'blink_perf.layout': {
'nested-percent-height-tables': {}
}})
test = utils.TestKey(
'ChromiumPerf/linux-perf/blink_perf.layout/nested-percent-height-tables'
).get()
test_container_key = utils.GetTestContainerKey(test.key)
sample_data = [
(818289, 2009771),
(818290, 1966080),
(818291, 1966080),
(818293, 1966080),
(818294, 2053461),
(818296, 2009771),
(818298, 1966080),
(818301, 2009771),
(818303, 2009771),
(818305, 2009771),
(818306, 2009771),
(818307, 1966080),
(818308, 2009771),
(818309, 2009771),
(818310, 1966080),
(818311, 2009771),
(818312, 1966080),
(818317, 1966080),
(818318, 1966080),
(818320, 2053461),
(818322, 2009771),
(818326, 1966080),
(818331, 1966080),
(818335, 1966080),
(818340, 2009771),
(818347, 2009771),
(818350, 1966080),
(818353, 1966080),
(818354, 2009771),
(818361, 2009771),
(818362, 1966080),
(818374, 2009771),
(818379, 2009771),
(818382, 2053461),
(818389, 2009771),
(818402, 1966080),
(818409, 2009771),
(818416, 1966080),
(818420, 1966080),
(818430, 2009771),
(818440, 2228224),
(818450, 2228224),
(818461, 2228224),
(818469, 2228224),
(818481, 2228224),
(818498, 2271915),
(818514, 2228224),
(818531, 2271915),
(818571, 2271915),
(818583, 2271915),
]
for row in sample_data:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.test_path)])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(1, len(new_anomalies))
self.assertEqual(anomaly.UP, new_anomalies[0].direction)
self.assertEqual(818431, new_anomalies[0].start_revision)
self.assertEqual(818440, new_anomalies[0].end_revision)
def testProcessTest__RefineAnomalyPlacement_BalancedEstimator2(self):
testing_common.AddTests(
['ChromiumPerf'], ['linux-perf'],
{'blink_perf.layout': {
'nested-percent-height-tables': {}
}})
test = utils.TestKey(
'ChromiumPerf/linux-perf/blink_perf.layout/nested-percent-height-tables'
).get()
test_container_key = utils.GetTestContainerKey(test.key)
sample_data = [
(793468, 136.5382),
(793486, 137.7192),
(793495, 137.4038),
(793504, 137.4919),
(793505, 137.4465),
(793518, 136.9279),
(793525, 137.3501),
(793528, 136.9622),
(793543, 137.1027),
(793550, 137.7351),
(793555, 137.1511),
(793559, 137.2094),
(793560, 136.5192),
(793565, 138.1536),
(793580, 137.4172),
(793590, 136.8746),
(793601, 137.5016),
(793609, 137.0773),
(793625, 137.4702),
(793646, 135.9019),
(793657, 137.2827),
(793702, 136.5978),
(793712, 136.0732),
(793721, 132.1820),
(793742, 122.1631),
(793760, 136.3152),
(793774, 136.9616),
(793788, 136.8438),
(794016, 136.3022),
(794024, 136.3495),
(794027, 136.3145),
(794036, 136.5502),
(794043, 136.3861),
(794051, 136.2035),
(794059, 136.2348),
(794066, 136.2594),
(794074, 135.9686),
(794088, 136.7375),
(794107, 136.5570),
(794132, 129.9924), # This one is a potential change point - but weak
(794143, 135.8275),
(794154, 107.2502), # This is a better change point
(794158, 108.3948),
(794160, 107.3564),
(794196, 107.9707),
(794236, 111.3168),
(794268, 108.7905),
(794281, 111.1065),
(794319, 109.7699),
(794320, 109.8082),
]
for row in sample_data:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
test.UpdateSheriff()
test.put()
s = Subscription(name='sheriff', visibility=VISIBILITY.PUBLIC)
with mock.patch.object(SheriffConfigClient, 'Match',
mock.MagicMock(return_value=([s], None))) as m:
find_anomalies.ProcessTests([test.key])
self.assertEqual(m.call_args_list, [mock.call(test.test_path)])
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(1, len(new_anomalies))
self.assertEqual(anomaly.DOWN, new_anomalies[0].direction)
self.assertEqual(794144, new_anomalies[0].start_revision)
self.assertEqual(794154, new_anomalies[0].end_revision)
def testProcessTest__RefineAnomalyPlacement_OnePassEDivisive(self):
testing_common.AddTests(
['ChromiumPerf'], ['linux-perf'],
{'blink_perf.layout': {
'nested-percent-height-tables': {}
}})
test = utils.TestKey(
'ChromiumPerf/linux-perf/blink_perf.layout/nested-percent-height-tables'
).get()
test_container_key = utils.GetTestContainerKey(test.key)
# 1608562683 will be anomaly if we run E-Divisive from 1608525044.
sample_data = [
(1608404024, 246272),
(1608407660, 249344),
(1608417360, 246272),
(1608422547, 246784),
(1608434678, 248832),
(1608440108, 248320),
(1608442260, 250880),
(1608452306, 248832),
(1608457404, 247296),
(1608459374, 247296),
(1608463502, 249344),
(1608469894, 247296),
(1608471945, 247296),
(1608477313, 246272),
(1608481014, 248832),
(1608484511, 247296),
(1608486532, 246784),
(1608488082, 248832),
(1608491972, 246784),
(1608493895, 248832),
(1608495366, 248320),
(1608498927, 252416),
(1608501293, 246784),
(1608505924, 246272),
(1608507885, 246784),
(1608509593, 250368),
(1608512971, 246784),
(1608515075, 246272),
(1608519889, 247296),
(1608521956, 254464),
(1608525044, 247296),
(1608526992, 244736),
(1608528640, 245760),
(1608530391, 246784),
(1608531986, 245760),
(1608533763, 245760),
(1608538109, 246272),
(1608539988, 246784),
(1608545280, 251392),
(1608547200, 251026),
(1608550736, 248320),
(1608552820, 248832),
(1608554780, 251392),
(1608560589, 247296),
(1608562683, 251904),
(1608564319, 268800),
(1608566089, 263168),
(1608567823, 266240),
(1608569370, 266752),
(1608570921, 264192),
]
for row in sample_data:
graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put()
test.UpdateSheriff()
test.put()
new_anomalies = anomaly.Anomaly.query().fetch()
self.assertEqual(0, len(new_anomalies))
def testMakeAnomalyEntity_NoRefBuild(self):
testing_common.AddTests(['ChromiumPerf'], ['linux'], {
'page_cycler_v2': {
'cnn': {},
'yahoo': {},
'nytimes': {},
},
})
test = utils.TestKey('ChromiumPerf/linux/page_cycler_v2').get()
testing_common.AddRows(test.test_path, [100, 200, 300, 400])
alert = find_anomalies._MakeAnomalyEntity(
_MakeSampleChangePoint(10011, 50, 100), test, 'avg', self._DataSeries(),
{}).get_result()
self.assertIsNone(alert.ref_test)
def testMakeAnomalyEntity_RefBuildSlash(self):
testing_common.AddTests(['ChromiumPerf'], ['linux'], {
'page_cycler_v2': {
'ref': {},
'cnn': {},
'yahoo': {},
'nytimes': {},
},
})
test = utils.TestKey('ChromiumPerf/linux/page_cycler_v2').get()
testing_common.AddRows(test.test_path, [100, 200, 300, 400])
alert = find_anomalies._MakeAnomalyEntity(
_MakeSampleChangePoint(10011, 50, 100), test, 'avg', self._DataSeries(),
{}).get_result()
self.assertEqual(alert.ref_test.string_id(),
'ChromiumPerf/linux/page_cycler_v2/ref')
def testMakeAnomalyEntity_RefBuildUnderscore(self):
testing_common.AddTests(['ChromiumPerf'], ['linux'], {
'page_cycler_v2': {
'cnn': {},
'cnn_ref': {},
'yahoo': {},
'nytimes': {},
},
})
test = utils.TestKey('ChromiumPerf/linux/page_cycler_v2/cnn').get()
testing_common.AddRows(test.test_path, [100, 200, 300, 400])
alert = find_anomalies._MakeAnomalyEntity(
_MakeSampleChangePoint(10011, 50, 100), test, 'avg', self._DataSeries(),
{}).get_result()
self.assertEqual(alert.ref_test.string_id(),
'ChromiumPerf/linux/page_cycler_v2/cnn_ref')
self.assertIsNone(alert.display_start)
self.assertIsNone(alert.display_end)
def testMakeAnomalyEntity_RevisionRanges(self):
testing_common.AddTests(['ClankInternal'], ['linux'], {
'page_cycler_v2': {
'cnn': {},
'cnn_ref': {},
'yahoo': {},
'nytimes': {},
},
})
test = utils.TestKey('ClankInternal/linux/page_cycler_v2/cnn').get()
testing_common.AddRows(test.test_path, [100, 200, 300, 400])
for row in graph_data.Row.query():
# Different enough to ensure it is picked up properly.
row.r_commit_pos = int(row.value) + 2
row.put()
alert = find_anomalies._MakeAnomalyEntity(
_MakeSampleChangePoint(300, 50, 100), test, 'avg', self._DataSeries(),
{}).get_result()
self.assertEqual(alert.display_start, 203)
self.assertEqual(alert.display_end, 302)
def testMakeAnomalyEntity_AddsOwnership(self):
data_samples = [{
'type': 'GenericSet',
'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826',
'values': ['alice@chromium.org', 'bob@chromium.org']
}, {
'type': 'GenericSet',
'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb827',
'values': ['abc']
}, {
'type': 'GenericSet',
'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb828',
'values': ['This is an info blurb.']
}]
test_key = utils.TestKey('ChromiumPerf/linux/page_cycler_v2/cnn')
testing_common.AddTests(['ChromiumPerf'], ['linux'], {
'page_cycler_v2': {
'cnn': {},
'cnn_ref': {},
'yahoo': {},
'nytimes': {},
},
})
test = test_key.get()
testing_common.AddRows(test.test_path, [100, 200, 300, 400])
suite_key = utils.TestKey('ChromiumPerf/linux/page_cycler_v2')
entity = histogram.SparseDiagnostic(
data=data_samples[0],
test=suite_key,
start_revision=1,
end_revision=sys.maxsize,
id=data_samples[0]['guid'],
name=reserved_infos.OWNERS.name)
entity.put()
entity = histogram.SparseDiagnostic(
data=data_samples[1],
test=suite_key,
start_revision=1,
end_revision=sys.maxsize,
id=data_samples[1]['guid'],
name=reserved_infos.BUG_COMPONENTS.name)
entity.put()
entity = histogram.SparseDiagnostic(
data=data_samples[2],
test=suite_key,
start_revision=1,
end_revision=sys.maxsize,
id=data_samples[2]['guid'],
name=reserved_infos.INFO_BLURB.name)
entity.put()
alert = find_anomalies._MakeAnomalyEntity(
_MakeSampleChangePoint(10011, 50, 100), test, 'avg', self._DataSeries(),
{}).get_result()
self.assertEqual(alert.ownership['component'], 'abc')
self.assertListEqual(alert.ownership['emails'],
['alice@chromium.org', 'bob@chromium.org'])
self.assertEqual(alert.ownership['info_blurb'], 'This is an info blurb.')
def testMakeAnomalyEntity_AlertGrouping(self):
data_sample = {
'type': 'GenericSet',
'guid': 'eb212e80-db58-4cbd-b331-c2245ecbb826',
'values': ['group123', 'group234']
}
testing_common.AddTests(['ChromiumPerf'], ['linux'], {
'page_cycler_v2': {
'cnn': {},
'cnn_ref': {},
'yahoo': {},
'nytimes': {},
},
})
test = utils.TestKey('ChromiumPerf/linux/page_cycler_v2/cnn').get()
testing_common.AddRows(test.test_path, [100, 200, 300, 400])
suite_key = utils.TestKey('ChromiumPerf/linux/page_cycler_v2')
entity = histogram.SparseDiagnostic(
data=data_sample,
test=suite_key,
start_revision=1,
end_revision=sys.maxsize,
id=data_sample['guid'],
name=reserved_infos.ALERT_GROUPING.name)
entity.put()
entity.put()
alert = find_anomalies._MakeAnomalyEntity(
_MakeSampleChangePoint(10011, 50, 100), test, 'avg', self._DataSeries(),
{}).get_result()
self.assertEqual(alert.alert_grouping, ['group123', 'group234'])
if __name__ == '__main__':
unittest.main()