1edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair# Copyright 2015 The Chromium Authors. All rights reserved. 2edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair# Use of this source code is governed by a BSD-style license that can be 3edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair# found in the LICENSE file. 4edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 5edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairimport sys 6edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairimport unittest 7edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 8edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairimport mock 9edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 10edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairfrom dashboard import find_anomalies 11edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairfrom dashboard import find_change_points 12edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairfrom dashboard import testing_common 13edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairfrom dashboard import utils 14edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairfrom dashboard.models import anomaly 15edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairfrom dashboard.models import graph_data 16edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairfrom dashboard.models import sheriff 17edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 18edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair# Sample time series. 19edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair_TEST_ROW_DATA = [ 20cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241105, 2136.7), (241116, 2140.3), (241151, 2149.1), 21cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241154, 2147.2), (241156, 2130.6), (241160, 2136.2), 22cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241188, 2146.7), (241201, 2141.8), (241226, 2140.6), 23cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241247, 2128.1), (241249, 2134.2), (241254, 2130.0), 24cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241262, 2136.0), (241268, 2142.6), (241271, 2149.1), 25cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241282, 2156.6), (241294, 2125.3), (241298, 2155.5), 26cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241303, 2148.5), (241317, 2146.2), (241323, 2123.3), 27cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241330, 2121.5), (241342, 2141.2), (241355, 2145.2), 28cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241371, 2136.3), (241386, 2144.0), (241405, 2138.1), 29cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241420, 2147.6), (241432, 2140.7), (241441, 2132.2), 30cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241452, 2138.2), (241455, 2139.3), (241471, 2134.0), 31cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241488, 2137.2), (241503, 2152.5), (241520, 2136.3), 32cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241524, 2139.3), (241529, 2143.5), (241532, 2145.5), 33cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241535, 2147.0), (241537, 2184.1), (241546, 2180.8), 34cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241553, 2181.5), (241559, 2176.8), (241566, 2174.0), 35cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241577, 2182.8), (241579, 2184.8), (241582, 2190.5), 36cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241584, 2183.1), (241609, 2178.3), (241620, 2178.1), 37cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241645, 2190.8), (241653, 2177.7), (241666, 2185.3), 38cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241697, 2173.8), (241716, 2172.1), (241735, 2172.5), 39cef7893435aa41160dd1255c43cb8498279738ccChris Craik (241757, 2174.7), (241766, 2196.7), (241782, 2184.1), 40edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair] 41edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 42edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 43edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairdef _MakeSampleChangePoint(x_value, median_before, median_after): 44edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Makes a sample find_change_points.ChangePoint for use in these tests.""" 45edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # The only thing that matters in these tests is the revision number 46edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # and the values before and after. 47edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair return find_change_points.ChangePoint( 48edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair x_value=x_value, 49edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair median_before=median_before, 50edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair median_after=median_after, 51edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair window_start=1, 52edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair window_end=8, 53edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair size_before=None, 54edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair size_after=None, 55edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair relative_change=None, 56edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair std_dev_before=None, 57edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair t_statistic=None, 58edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair degrees_of_freedom=None, 59edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair p_value=None) 60edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 61edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 62edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairclass EndRevisionMatcher(object): 63edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Custom matcher to test if an anomaly matches a given end rev.""" 64edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 65edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def __init__(self, end_revision): 66edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Initializes with the end time to check.""" 67edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._end_revision = end_revision 68edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 69edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def __eq__(self, rhs): 70edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Checks to see if RHS has the same end time.""" 71edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair return self._end_revision == rhs.end_revision 72edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 73edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def __repr__(self): 74edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Shows a readable revision which can be printed when assert fails.""" 75edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair return '<IsEndRevision %d>' % self._end_revision 76edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 77edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 78edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairclass ModelMatcher(object): 79edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Custom matcher to check if two ndb entity names match.""" 80edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 81edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def __init__(self, name): 82edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Initializes with the name of the entity.""" 83edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._name = name 84edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 85edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def __eq__(self, rhs): 86edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Checks to see if RHS has the same name.""" 87edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair return rhs.key.string_id() == self._name 88edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 89edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def __repr__(self): 90edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair """Shows a readable revision which can be printed when assert fails.""" 91edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair return '<IsModel %s>' % self._name 92edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 93edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 94edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairclass ProcessAlertsTest(testing_common.TestCase): 95edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 96edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def setUp(self): 97edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair super(ProcessAlertsTest, self).setUp() 98edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.SetCurrentUser('foo@bar.com', is_admin=True) 99edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 100edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def _AddDataForTests(self): 101edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair testing_common.AddTests( 102edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ['ChromiumGPU'], 103edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ['linux-release'], { 104edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'scrolling_benchmark': { 105edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ref': {}, 106edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair }, 107edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair }) 108edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref = utils.TestKey( 109edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 110edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair for i in range(9000, 10070, 5): 111edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # Internal-only data should be found. 112edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test_container_key = utils.GetTestContainerKey(ref.key) 113edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair graph_data.Row( 114edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair id=i + 1, value=float(i * 3), 115edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair parent=test_container_key, internal_only=True).put() 116edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 117edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch.object( 118edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.find_change_points, 'FindChangePoints', 119edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.MagicMock(return_value=[ 120edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair _MakeSampleChangePoint(10011, 50, 100), 121edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair _MakeSampleChangePoint(10041, 200, 100), 122edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair _MakeSampleChangePoint(10061, 0, 100), 123edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ])) 124edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch.object(find_anomalies.email_sheriff, 'EmailSheriff') 125edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def testProcessTest(self, mock_email_sheriff): 126edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._AddDataForTests() 127edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test_path = 'ChromiumGPU/linux-release/scrolling_benchmark/ref' 128edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test = utils.TestKey(test_path).get() 129edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 130edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[test_path]).put() 131edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.put() 132edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 133edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(test.key) 134edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 135edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair expected_calls = [ 136edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.call(ModelMatcher('sheriff'), 137edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ModelMatcher('ref'), 138edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair EndRevisionMatcher(10011)), 139edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.call(ModelMatcher('sheriff'), 140edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ModelMatcher('ref'), 141edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair EndRevisionMatcher(10041)), 142edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.call(ModelMatcher('sheriff'), 143edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ModelMatcher('ref'), 144edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair EndRevisionMatcher(10061))] 145edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(expected_calls, mock_email_sheriff.call_args_list) 146edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 147edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies = anomaly.Anomaly.query().fetch() 148edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(len(anomalies), 3) 149edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 150edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def AnomalyExists( 151edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies, test, percent_changed, direction, 152edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair start_revision, end_revision, sheriff_name, internal_only): 153edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair for a in anomalies: 154edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair if (a.test == test and 155edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair a.percent_changed == percent_changed and 156edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair a.direction == direction and 157edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair a.start_revision == start_revision and 158edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair a.end_revision == end_revision and 159edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair a.sheriff.string_id() == sheriff_name and 160edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair a.internal_only == internal_only): 161edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair return True 162edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair return False 163edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 164edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertTrue( 165edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair AnomalyExists( 166edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies, test.key, percent_changed=100, direction=anomaly.UP, 167edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair start_revision=10007, end_revision=10011, sheriff_name='sheriff', 168edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair internal_only=False)) 169edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 170edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertTrue( 171edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair AnomalyExists( 172edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies, test.key, percent_changed=-50, direction=anomaly.DOWN, 173edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair start_revision=10037, end_revision=10041, sheriff_name='sheriff', 174edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair internal_only=False)) 175edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 176edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertTrue( 177edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair AnomalyExists( 178edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies, test.key, percent_changed=sys.float_info.max, 179edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair direction=anomaly.UP, start_revision=10057, end_revision=10061, 180edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff_name='sheriff', internal_only=False)) 181edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 182edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # This is here just to verify that AnomalyExists returns False sometimes. 183edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertFalse( 184edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair AnomalyExists( 185edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies, test.key, percent_changed=100, direction=anomaly.DOWN, 186edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair start_revision=10037, end_revision=10041, sheriff_name='sheriff', 187edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair internal_only=False)) 188edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 189edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch.object( 190edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.find_change_points, 'FindChangePoints', 191edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.MagicMock(return_value=[ 192edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair _MakeSampleChangePoint(10011, 100, 50) 193edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ])) 19446b43bff003ceda46cf9a5d40a47f7674996d2e0Zhen Wang def testProcessTest_ImprovementMarkedAsImprovement(self): 195edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._AddDataForTests() 196edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test = utils.TestKey( 197edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 198edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 199edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[test.test_path]).put() 200edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.improvement_direction = anomaly.DOWN 201edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.put() 202edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(test.key) 203edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies = anomaly.Anomaly.query().fetch() 204edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(len(anomalies), 1) 205edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertTrue(anomalies[0].is_improvement) 206edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 207edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch('logging.error') 208edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def testProcessTest_NoSheriff_ErrorLogged(self, mock_logging_error): 209edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._AddDataForTests() 210edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref = utils.TestKey( 211edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 212edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(ref.key) 213edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock_logging_error.assert_called_with('No sheriff for %s', ref.key) 214edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 215edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch.object( 216edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.find_change_points, 'FindChangePoints', 217edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.MagicMock(return_value=[ 218edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair _MakeSampleChangePoint(10026, 55.2, 57.8), 219edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair _MakeSampleChangePoint(10041, 45.2, 37.8), 220edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ])) 221edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch.object(find_anomalies.email_sheriff, 'EmailSheriff') 222cef7893435aa41160dd1255c43cb8498279738ccChris Craik def testProcessTest_FiltersOutImprovements(self, mock_email_sheriff): 223edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._AddDataForTests() 224edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test = utils.TestKey( 225edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 226edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 227edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[test.test_path]).put() 228edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.improvement_direction = anomaly.UP 229edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.put() 230edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(test.key) 231edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock_email_sheriff.assert_called_once_with( 232edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ModelMatcher('sheriff'), ModelMatcher('ref'), EndRevisionMatcher(10041)) 233edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 234edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch.object( 235edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.find_change_points, 'FindChangePoints', 236edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.MagicMock(return_value=[ 237edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair _MakeSampleChangePoint(10011, 50, 100), 238edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ])) 239edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch.object(find_anomalies.email_sheriff, 'EmailSheriff') 240edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def testProcessTest_InternalOnlyTest(self, mock_email_sheriff): 241edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._AddDataForTests() 242edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test = utils.TestKey( 243edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 244edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.internal_only = True 245edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 246edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[test.test_path]).put() 247edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.put() 248edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 249edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(test.key) 250edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair expected_calls = [ 251edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.call(ModelMatcher('sheriff'), 252edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ModelMatcher('ref'), 253edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair EndRevisionMatcher(10011))] 254edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(expected_calls, mock_email_sheriff.call_args_list) 255edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 256edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair anomalies = anomaly.Anomaly.query().fetch() 257edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(len(anomalies), 1) 258edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(test.key, anomalies[0].test) 259edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(100, anomalies[0].percent_changed) 260edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(anomaly.UP, anomalies[0].direction) 261edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(10007, anomalies[0].start_revision) 262edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(10011, anomalies[0].end_revision) 263edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertTrue(anomalies[0].internal_only) 264edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 265edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def testProcessTest_AnomaliesMatchRefSeries_NoAlertCreated(self): 266edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # Tests that a Anomaly entity is not created if both the test and its 267edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # corresponding ref build series have the same data. 268edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair testing_common.AddTests( 269edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ['ChromiumGPU'], ['linux-release'], { 270edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'scrolling_benchmark': {'ref': {}}, 271edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair }) 272edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref = utils.TestKey( 273edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 274edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair non_ref = utils.TestKey( 275edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark').get() 276edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test_container_key = utils.GetTestContainerKey(ref.key) 277edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test_container_key_non_ref = utils.GetTestContainerKey(non_ref.key) 278edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair for row in _TEST_ROW_DATA: 279edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put() 280edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair graph_data.Row(id=row[0], value=row[1], 281edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair parent=test_container_key_non_ref).put() 282edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 283edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[non_ref.test_path]).put() 284edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref.put() 285edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair non_ref.put() 286edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(non_ref.key) 287edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair new_anomalies = anomaly.Anomaly.query().fetch() 288edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(0, len(new_anomalies)) 289edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 290edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def testProcessTest_AnomalyDoesNotMatchRefSeries_AlertCreated(self): 291edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # Tests that an Anomaly entity is created when non-ref series goes up, but 292edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # the ref series stays flat. 293edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair testing_common.AddTests( 294edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ['ChromiumGPU'], ['linux-release'], { 295edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'scrolling_benchmark': {'ref': {}}, 296edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair }) 297edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref = utils.TestKey( 298edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 299edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair non_ref = utils.TestKey( 300edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark').get() 301edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test_container_key = utils.GetTestContainerKey(ref.key) 302edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test_container_key_non_ref = utils.GetTestContainerKey(non_ref.key) 303edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair for row in _TEST_ROW_DATA: 304edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair graph_data.Row(id=row[0], value=2125.375, parent=test_container_key).put() 305edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair graph_data.Row(id=row[0], value=row[1], 306edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair parent=test_container_key_non_ref).put() 307edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 308edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[ref.test_path]).put() 309edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 310edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[non_ref.test_path]).put() 311edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref.put() 312edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair non_ref.put() 313edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(non_ref.key) 314edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair new_anomalies = anomaly.Anomaly.query().fetch() 315edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(len(new_anomalies), 1) 316edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 317edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def testProcessTest_CreatesAnAnomaly(self): 318edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair testing_common.AddTests( 319edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ['ChromiumGPU'], ['linux-release'], { 320edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'scrolling_benchmark': {'ref': {}}, 321edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair }) 322edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref = utils.TestKey( 323edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 324edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test_container_key = utils.GetTestContainerKey(ref.key) 325edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair for row in _TEST_ROW_DATA: 326edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair graph_data.Row(id=row[0], value=row[1], parent=test_container_key).put() 327edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair sheriff.Sheriff( 328edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair email='a@google.com', id='sheriff', patterns=[ref.test_path]).put() 329edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ref.put() 330edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(ref.key) 331edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair new_anomalies = anomaly.Anomaly.query().fetch() 332edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(1, len(new_anomalies)) 333edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(anomaly.UP, new_anomalies[0].direction) 334edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(241536, new_anomalies[0].start_revision) 335edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertEqual(241537, new_anomalies[0].end_revision) 336edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 337edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair @mock.patch('logging.error') 338edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair def testProcessTest_LastAlertedRevisionTooHigh_PropertyReset( 339edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self, mock_logging_error): 340edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # If the last_alerted_revision property of the Test is too high, 341edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair # then the property should be reset and an error should be logged. 342edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self._AddDataForTests() 343edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test = utils.TestKey( 344edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref').get() 345edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.last_alerted_revision = 1234567890 346edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair test.put() 347edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair find_anomalies.ProcessTest(test.key) 348edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair self.assertIsNone(test.key.get().last_alerted_revision) 349edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair calls = [ 350edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.call( 351edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'last_alerted_revision %d is higher than highest rev %d for test ' 352edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair '%s; setting last_alerted_revision to None.', 353edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 1234567890, 354edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 10066, 355edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref'), 356edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock.call( 357edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'No rows fetched for %s', 358edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 'ChromiumGPU/linux-release/scrolling_benchmark/ref') 359edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair ] 360edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair mock_logging_error.assert_has_calls(calls, any_order=True) 361edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 362edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair 363edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclairif __name__ == '__main__': 364edfe2194ee8a857cc1e78b4e4020f9b5e7210029Dan Sinclair unittest.main() 365