Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(45)

Side by Side Diff: scripts/slave/recipe_modules/auto_bisect/bisector_test.py

Issue 940123005: Adding ability to bisect recipe to bisect into dependency repos. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@hax
Patch Set: Missing docstring Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import os 5 import os
6 import sys 6 import sys
7 import unittest 7 import unittest
8 8
9 # TODO(robertocn): Use abspath for these, to prevent relative path errors. 9 # TODO(robertocn): Use abspath for these, to prevent relative path errors.
10 _RECIPE_MODULES_DIR = os.path.join(os.path.dirname(__file__), os.path.pardir) 10 _RECIPE_MODULES_DIR = os.path.join(os.path.dirname(__file__), os.path.pardir)
11 # For the importing of mock. 11 # For the importing of mock.
12 _ROOT_DIR = os.path.join(os.path.dirname(__file__), os.path.pardir, 12 _ROOT_DIR = os.path.join(os.path.dirname(__file__), os.path.pardir,
13 os.path.pardir, os.path.pardir, os.path.pardir) 13 os.path.pardir, os.path.pardir, os.path.pardir)
14 14
15 sys.path.append(_RECIPE_MODULES_DIR) 15 sys.path.append(_RECIPE_MODULES_DIR)
16 sys.path.append(os.path.join(_ROOT_DIR, 'third_party', 'mock-1.0.1')) 16 sys.path.append(os.path.join(_ROOT_DIR, 'third_party', 'mock-1.0.1'))
17 17
18 import mock 18 import mock
19 19
20 from auto_bisect.bisector import Bisector 20 from auto_bisect.bisector import Bisector
21 21
22 class BisectorTest(unittest.TestCase): # pragma: no cover 22
23 class MockRevisionClass(object): # pragma: no cover
24 def __init__(self, rev_string, bisector):
25 self.commit_pos = int(rev_string)
26 self.revision_string = rev_string
27 self.bisector = bisector
28 self.previous_revision = None
29 self.next_revision = None
30 self.values = []
31
32 def get_next_url(self):
33 if self.in_progress:
34 return 'mockurl'
35 return None
36
37
38 class BisectorTest(unittest.TestCase): # pragma: no cover
qyearsley 2015/03/10 23:20:48 Nit: Two spaces before #.
RobertoCN 2015/03/13 20:55:59 Done.
23 def setUp(self): 39 def setUp(self):
24 self.bisect_config = { 40 self.bisect_config = {
25 'test_type': 'perf', 41 'test_type': 'perf',
26 'command': 'tools/perf/run_benchmark -v ' 42 'command': 'tools/perf/run_benchmark -v '
27 '--browser=release page_cycler.intl_ar_fa_he', 43 '--browser=release page_cycler.intl_ar_fa_he',
28 'good_revision': '306475', 44 'good_revision': '306475',
29 'bad_revision': '306478', 45 'bad_revision': '306478',
30 'metric': 'warm_times/page_load_time', 46 'metric': 'warm_times/page_load_time',
31 'repeat_count': '2', 47 'repeat_count': '2',
32 'max_time_minutes': '5', 48 'max_time_minutes': '5',
33 'truncate_percent': '25', 49 'truncate_percent': '25',
34 'bug_id': '425582', 50 'bug_id': '425582',
35 'gs_bucket': 'chrome-perf', 51 'gs_bucket': 'chrome-perf',
36 'builder_host': 'master4.golo.chromium.org', 52 'builder_host': 'master4.golo.chromium.org',
37 'builder_port': '8341', 53 'builder_port': '8341',
38 'dummy_builds': True, 54 'dummy_builds': True,
39 } 55 }
40 self.dummy_api = mock.Mock() 56 self.dummy_api = mock.Mock()
41 57
42 class MockRevisionClass(object):
43 def __init__(self, rev_string, bisector):
44 self.commit_pos = int(rev_string)
45 self.revision_string = rev_string
46 self.bisector = bisector
47 self.previous_revision = None
48 self.next_revision = None
49 self.values = []
50 58
51 def get_next_url(self):
52 if self.in_progress:
53 return 'mockurl'
54 return None
55 59
56 def test_create_bisector(self): 60 def test_create_bisector(self):
57 new_bisector = Bisector(self.dummy_api, self.bisect_config, 61 new_bisector = Bisector(self.dummy_api, self.bisect_config,
58 self.MockRevisionClass) 62 MockRevisionClass)
59 # Check the proper revision range is initialized 63 # Check the proper revision range is initialized
60 self.assertEqual(4, len(new_bisector.revisions)) 64 self.assertEqual(4, len(new_bisector.revisions))
61 a, b, c, d = new_bisector.revisions 65 a, b, c, d = new_bisector.revisions
62 # Check that revisions are properly chained 66 # Check that revisions are properly chained
63 self.assertEqual(a, b.previous_revision) 67 self.assertEqual(a, b.previous_revision)
64 self.assertEqual(b, c.previous_revision) 68 self.assertEqual(b, c.previous_revision)
65 self.assertEqual(c, d.previous_revision) 69 self.assertEqual(c, d.previous_revision)
66 self.assertEqual(d, c.next_revision) 70 self.assertEqual(d, c.next_revision)
67 self.assertEqual(c, b.next_revision) 71 self.assertEqual(c, b.next_revision)
68 self.assertEqual(b, a.next_revision) 72 self.assertEqual(b, a.next_revision)
69 73
70 # Check the ends are grounded 74 # Check the ends are grounded
71 self.assertIsNone(a.previous_revision) 75 self.assertIsNone(a.previous_revision)
72 self.assertIsNone(d.next_revision) 76 self.assertIsNone(d.next_revision)
73 77
74 # Check the reference range is set with correct 'goodness' values 78 # Check the reference range is set with correct 'goodness' values
75 self.assertTrue(a.good) 79 self.assertTrue(a.good)
76 self.assertTrue(d.bad) 80 self.assertTrue(d.bad)
77 81
78 def test_improvement_direction_default(self): 82 def test_improvement_direction_default(self):
79 # By default, no improvement direction should be set 83 # By default, no improvement direction should be set
80 new_bisector = Bisector(self.dummy_api, self.bisect_config, 84 new_bisector = Bisector(self.dummy_api, self.bisect_config,
qyearsley 2015/03/10 23:20:48 If new_bisector is renamed to bisector, then MockR
RobertoCN 2015/03/13 20:55:59 Done.
81 self.MockRevisionClass) 85 MockRevisionClass)
82 self.assertIsNone(new_bisector.improvement_direction) 86 self.assertIsNone(new_bisector.improvement_direction)
83 87
84 def test_improvement_direction_greater_is_better(self): 88 def test_improvement_direction_greater_is_better(self):
85 # Improvement up, bad > good: should fail 89 # Improvement up, bad > good: should fail
86 self.bisect_config['improvement_direction'] = 1 90 self.bisect_config['improvement_direction'] = 1
87 new_bisector = Bisector(self.dummy_api, self.bisect_config, 91 new_bisector = Bisector(self.dummy_api, self.bisect_config,
88 self.MockRevisionClass) 92 MockRevisionClass)
89 new_bisector.good_rev.mean_value = 10 93 new_bisector.good_rev.mean_value = 10
90 new_bisector.bad_rev.mean_value = 100 94 new_bisector.bad_rev.mean_value = 100
91 self.assertFalse(new_bisector.check_improvement_direction()) 95 self.assertFalse(new_bisector.check_improvement_direction())
92 self.assertIn('direction of improvement', ''.join(new_bisector.warnings)) 96 self.assertIn('direction of improvement', ''.join(new_bisector.warnings))
93 97
94 # Improvement up, bad < good: should not fail 98 # Improvement up, bad < good: should not fail
95 self.bisect_config['improvement_direction'] = 1 99 self.bisect_config['improvement_direction'] = 1
96 new_bisector = Bisector(self.dummy_api, self.bisect_config, 100 new_bisector = Bisector(self.dummy_api, self.bisect_config,
97 self.MockRevisionClass) 101 MockRevisionClass)
98 new_bisector.good_rev.mean_value = 100 102 new_bisector.good_rev.mean_value = 100
99 new_bisector.bad_rev.mean_value = 10 103 new_bisector.bad_rev.mean_value = 10
100 self.assertTrue(new_bisector.check_improvement_direction()) 104 self.assertTrue(new_bisector.check_improvement_direction())
101 self.assertNotIn('direction of improvement', ''.join(new_bisector.warnings)) 105 self.assertNotIn('direction of improvement', ''.join(new_bisector.warnings))
102 106
103 def test_improvement_direction_lower_is_better(self): 107 def test_improvement_direction_lower_is_better(self):
104 # Improvement down, bad < good: should fail 108 # Improvement down, bad < good: should fail
105 self.bisect_config['improvement_direction'] = -1 109 self.bisect_config['improvement_direction'] = -1
106 new_bisector = Bisector(self.dummy_api, self.bisect_config, 110 new_bisector = Bisector(self.dummy_api, self.bisect_config,
107 self.MockRevisionClass) 111 MockRevisionClass)
108 new_bisector.good_rev.mean_value = 100 112 new_bisector.good_rev.mean_value = 100
109 new_bisector.bad_rev.mean_value = 10 113 new_bisector.bad_rev.mean_value = 10
110 self.assertFalse(new_bisector.check_improvement_direction()) 114 self.assertFalse(new_bisector.check_improvement_direction())
111 self.assertIn('direction of improvement', ''.join(new_bisector.warnings)) 115 self.assertIn('direction of improvement', ''.join(new_bisector.warnings))
112 116
113 # Improvement down, bad > good: should not fail 117 # Improvement down, bad > good: should not fail
114 self.bisect_config['improvement_direction'] = -1 118 self.bisect_config['improvement_direction'] = -1
115 new_bisector = Bisector(self.dummy_api, self.bisect_config, 119 new_bisector = Bisector(self.dummy_api, self.bisect_config,
116 self.MockRevisionClass) 120 MockRevisionClass)
117 new_bisector.good_rev.mean_value = 10 121 new_bisector.good_rev.mean_value = 10
118 new_bisector.bad_rev.mean_value = 100 122 new_bisector.bad_rev.mean_value = 100
119 self.assertTrue(new_bisector.check_improvement_direction()) 123 self.assertTrue(new_bisector.check_improvement_direction())
120 self.assertNotIn('direction of improvement', ''.join(new_bisector.warnings)) 124 self.assertNotIn('direction of improvement', ''.join(new_bisector.warnings))
121 125
122 def test_check_regression_confidence_default(self): 126 def test_check_regression_confidence_default(self):
123 # Test default required confidence (default may change) 127 # Test default required confidence (default may change)
124 mock_score = self.dummy_api.m.math_utils.confidence_score 128 mock_score = self.dummy_api.m.math_utils.confidence_score
125 # A confidence score of 0 should not satisfy any default 129 # A confidence score of 0 should not satisfy any default
126 mock_score.return_value = 0 130 mock_score.return_value = 0
127 new_bisector = Bisector(self.dummy_api, self.bisect_config, 131 new_bisector = Bisector(self.dummy_api, self.bisect_config,
128 self.MockRevisionClass) 132 MockRevisionClass)
129 self.assertFalse(new_bisector.check_regression_confidence()) 133 self.assertFalse(new_bisector.check_regression_confidence())
130 self.assertTrue(new_bisector.failed_confidence) 134 self.assertTrue(new_bisector.failed_confidence)
131 135
132 # A confidence score of 100 should satisfy any default 136 # A confidence score of 100 should satisfy any default
133 mock_score.return_value = 100 137 mock_score.return_value = 100
134 new_bisector = Bisector(self.dummy_api, self.bisect_config, 138 new_bisector = Bisector(self.dummy_api, self.bisect_config,
135 self.MockRevisionClass) 139 MockRevisionClass)
136 self.assertTrue(new_bisector.check_regression_confidence()) 140 self.assertTrue(new_bisector.check_regression_confidence())
137 self.assertFalse(new_bisector.failed_confidence) 141 self.assertFalse(new_bisector.failed_confidence)
138 142
139 def test_check_regression_confidence_not_required(self): 143 def test_check_regression_confidence_not_required(self):
140 # When confidence is not required, confidence_score should not be called 144 # When confidence is not required, confidence_score should not be called
141 mock_score = self.dummy_api.m.math_utils.confidence_score 145 mock_score = self.dummy_api.m.math_utils.confidence_score
142 self.bisect_config['required_regression_confidence'] = None 146 self.bisect_config['required_regression_confidence'] = None
143 new_bisector = Bisector(self.dummy_api, self.bisect_config, 147 new_bisector = Bisector(self.dummy_api, self.bisect_config,
144 self.MockRevisionClass) 148 MockRevisionClass)
145 self.assertTrue(new_bisector.check_regression_confidence()) 149 self.assertTrue(new_bisector.check_regression_confidence())
146 self.assertFalse(mock_score.called) 150 self.assertFalse(mock_score.called)
147 151
148 def test_check_regression_confidence_arbitrary(self): 152 def test_check_regression_confidence_arbitrary(self):
149 mock_score = self.dummy_api.m.math_utils.confidence_score 153 mock_score = self.dummy_api.m.math_utils.confidence_score
150 self.bisect_config['required_regression_confidence'] = 99 154 self.bisect_config['required_regression_confidence'] = 99
151 # A confidence score of 98.5 should not satisfy the required 99 155 # A confidence score of 98.5 should not satisfy the required 99
152 mock_score.return_value = 98.5 156 mock_score.return_value = 98.5
153 new_bisector = Bisector(self.dummy_api, self.bisect_config, 157 new_bisector = Bisector(self.dummy_api, self.bisect_config,
154 self.MockRevisionClass) 158 MockRevisionClass)
155 self.assertFalse(new_bisector.check_regression_confidence()) 159 self.assertFalse(new_bisector.check_regression_confidence())
156 self.assertTrue(new_bisector.failed_confidence) 160 self.assertTrue(new_bisector.failed_confidence)
157 161
158 # A confidence score of 99.5 should satisfy the required 99 162 # A confidence score of 99.5 should satisfy the required 99
159 mock_score.return_value = 99.5 163 mock_score.return_value = 99.5
160 new_bisector = Bisector(self.dummy_api, self.bisect_config, 164 new_bisector = Bisector(self.dummy_api, self.bisect_config,
161 self.MockRevisionClass) 165 MockRevisionClass)
162 self.assertTrue(new_bisector.check_regression_confidence()) 166 self.assertTrue(new_bisector.check_regression_confidence())
163 self.assertFalse(new_bisector.failed_confidence) 167 self.assertFalse(new_bisector.failed_confidence)
164 168
165 def test_wait_for_all(self): 169 def test_wait_for_all(self):
166 def mock_update_status(s): 170 def mock_update_status(s):
167 if getattr(s, 'mock_verified', False): 171 if getattr(s, 'mock_verified', False):
168 s.in_progress = False 172 s.in_progress = False
169 return 173 return
170 s.mock_verified = True 174 s.mock_verified = True
171 s.tested = True 175 s.tested = True
172 176
173 # Plug in mock update_status method 177 # Plug in mock update_status method
174 with mock.patch( 178 with mock.patch(
175 'bisector_test.BisectorTest.MockRevisionClass.update_status', 179 'bisector_test.MockRevisionClass.update_status',
176 mock_update_status): 180 mock_update_status):
177 new_bisector = Bisector(self.dummy_api, self.bisect_config, 181 new_bisector = Bisector(self.dummy_api, self.bisect_config,
178 self.MockRevisionClass) 182 MockRevisionClass)
179 for r in new_bisector.revisions: 183 for r in new_bisector.revisions:
180 r.in_progress = True 184 r.in_progress = True
181 new_bisector.wait_for_all(new_bisector.revisions) 185 new_bisector.wait_for_all(new_bisector.revisions)
182 # Verify that all revisions in list where verified by mock_update_status 186 # Verify that all revisions in list where verified by mock_update_status
183 self.assertTrue(all([r.mock_verified for r in new_bisector.revisions])) 187 self.assertTrue(all([r.mock_verified for r in new_bisector.revisions]))
184 188
185 def test_wait_for_any(self): 189 def test_wait_for_any(self):
186 # Creating placeholder for the patch 190 # Creating placeholder for the patch
187 self.MockRevisionClass.update_status = None 191 MockRevisionClass.update_status = None
188 with mock.patch( 192 with mock.patch(
189 'bisector_test.BisectorTest.MockRevisionClass.update_status'): 193 'bisector_test.MockRevisionClass.update_status'):
190 new_bisector = Bisector(self.dummy_api, self.bisect_config, 194 new_bisector = Bisector(self.dummy_api, self.bisect_config,
191 self.MockRevisionClass) 195 MockRevisionClass)
192 for r in new_bisector.revisions: 196 for r in new_bisector.revisions:
193 r.tested = False 197 r.tested = False
194 r.in_progress = True 198 r.in_progress = True
195 new_bisector.revisions[0].tested = True 199 new_bisector.revisions[0].tested = True
196 finished_revision = new_bisector.wait_for_any(new_bisector.revisions) 200 finished_revision = new_bisector.wait_for_any(new_bisector.revisions)
197 self.assertEqual(new_bisector.revisions[0], finished_revision) 201 self.assertEqual(new_bisector.revisions[0], finished_revision)
198 202
203
204 class BisectorAbortTest(unittest.TestCase): # pragma: no cover
qyearsley 2015/03/10 23:20:48 Nit: Two spaces before #. Also, it seems strange t
RobertoCN 2015/03/13 20:55:59 These tests are not covered when calculating cover
205 def setUp(self):
206 self.bisect_config = {
207 'test_type': 'perf',
208 'command': 'tools/perf/run_benchmark -v '
209 '--browser=release page_cycler.intl_ar_fa_he',
210 'good_revision': '306475',
211 'bad_revision': '306478',
212 'metric': 'warm_times/page_load_time',
213 'repeat_count': '2',
214 'max_time_minutes': '5',
215 'truncate_percent': '25',
216 'bug_id': '425582',
217 'gs_bucket': 'chrome-perf',
218 'builder_host': 'master4.golo.chromium.org',
219 'builder_port': '8341',
220 'dummy_builds': True,
221 }
222 self.dummy_api = mock.Mock()
223 self.called_abort = False
224 self.aborted_once = False
225
199 def test_abort_unnecessary_jobs(self): 226 def test_abort_unnecessary_jobs(self):
200 global aborted_once, called_abort 227 def mock_abort(_):
201 called_abort = False 228 self.called_abort = True
202 aborted_once = False 229 if self.aborted_once:
230 raise RuntimeError('Only one abort expected')
231 self.aborted_once = True
203 232
204 def mock_abort(s): 233 MockRevisionClass.abort = None
205 global aborted_once, called_abort 234 MockRevisionClass.update_status = None
206 called_abort = True
207 if aborted_once:
208 raise Exception('Only one abort expected')
209 aborted_once = True
210
211 self.MockRevisionClass.abort = None
212 self.MockRevisionClass.update_status = None
213 with mock.patch( 235 with mock.patch(
214 'bisector_test.BisectorTest.MockRevisionClass.update_status'): 236 'bisector_test.MockRevisionClass.update_status'):
215 with mock.patch('bisector_test.BisectorTest.MockRevisionClass.abort', 237 with mock.patch('bisector_test.MockRevisionClass.abort',
216 mock_abort) as abort_patch: 238 mock_abort):
217 new_bisector = Bisector(self.dummy_api, self.bisect_config, 239 new_bisector = Bisector(self.dummy_api, self.bisect_config,
218 self.MockRevisionClass) 240 MockRevisionClass)
219 r = new_bisector.revisions 241 r = new_bisector.revisions
220 r[0].good = True 242 r[0].good = True
221 r[0].bad = False 243 r[0].bad = False
222 r[0].tested = True 244 r[0].tested = True
223 r[0].in_progress = False 245 r[0].in_progress = False
224 246
225 r[1].in_progress = True 247 r[1].in_progress = True
226 r[1].tested = False 248 r[1].tested = False
227 249
228 r[2].good = True 250 r[2].good = True
229 r[2].bad = False 251 r[2].bad = False
230 r[2].tested = True 252 r[2].tested = True
231 r[2].in_progress = False 253 r[2].in_progress = False
232 254
233 r[3].bad = True 255 r[3].bad = True
234 r[3].good = False 256 r[3].good = False
235 r[3].tested = True 257 r[3].tested = True
236 r[3].in_progress = False 258 r[3].in_progress = False
237 259
238 try: 260 try:
239 new_bisector.abort_unnecessary_jobs() 261 new_bisector.abort_unnecessary_jobs()
240 except: 262 except RuntimeError:
241 self.fail('Expected to call abort only once') 263 self.fail('Expected to call abort only once')
242 self.assertTrue(called_abort) 264 self.assertTrue(self.called_abort)
243 265
244 # Verifying the side effects of updating the candidate range 266 # Verifying the side effects of updating the candidate range
245 self.assertEqual(r[2], new_bisector.lkgr) 267 self.assertEqual(r[2], new_bisector.lkgr)
246 self.assertEqual(r[3], new_bisector.fkbr) 268 self.assertEqual(r[3], new_bisector.fkbr)
247 269
248 # TODO: Test check_bisect_finished 270 # TODO(robertocn): Add test for bisector.check_bisect_finished.
qyearsley 2015/03/10 23:20:48 Probably want two blank lines between the test cas
RobertoCN 2015/03/13 20:55:59 Done.
249
250
251 if __name__ == '__main__': 271 if __name__ == '__main__':
252 unittest.main() # pragma: no cover 272 unittest.main() # pragma: no cover
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698