OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | |
3 # Use of this source code is governed by a BSD-style license that can be | |
4 # found in the LICENSE file. | |
5 | |
6 import copy | |
7 import os | |
8 import sys | |
9 import unittest | |
10 | |
11 root_dir = os.path.abspath(os.path.join( | |
12 os.path.dirname(__file__), os.path.pardir, | |
13 os.path.pardir, os.path.pardir, os.path.pardir)) | |
14 sys.path.insert(0, os.path.join(root_dir, 'third_party', 'mock-1.0.1')) | |
15 sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.path.pardir)) | |
16 | |
17 import mock | |
18 | |
19 import auto_bisect.bisector | |
20 import auto_bisect.depot_config | |
21 | |
22 | |
23 class MockRevisionClass(object): # pragma: no cover | |
24 | |
25 def __init__( | |
26 self, bisector, commit_hash, | |
27 depot_name='chromium', base_revision=None): | |
28 self.bisector = bisector | |
29 self.commit_hash = commit_hash | |
30 self.depot_name = depot_name | |
31 self.base_revision = base_revision | |
32 self.previous_revision = None | |
33 self.next_revision = None | |
34 self.values = [] | |
35 self.overall_return_code = None | |
36 self.deps = {} | |
37 self.status = '' | |
38 | |
39 def read_deps(self, tester_name): | |
40 pass | |
41 | |
42 def retest(self): | |
43 self.bisector.last_tested_revision = self | |
44 self.values.append(3) | |
45 | |
46 | |
47 @mock.patch.object(auto_bisect.bisector.Bisector, 'ensure_sync_master_branch', | |
48 mock.MagicMock()) | |
49 class BisectorTest(unittest.TestCase): # pragma: no cover | |
50 | |
51 def setUp(self): | |
52 self.bisect_config = { | |
53 'test_type': 'perf', | |
54 'command': ('tools/perf/run_benchmark -v ' | |
55 '--browser=release page_cycler.intl_ar_fa_he'), | |
56 'good_revision': 'abcd5678abcd5678abcd5678abcd5678abcd5678', | |
57 'bad_revision': 'def05678def05678def05678def05678def05678', | |
58 'metric': 'warm_times/page_load_time', | |
59 'repeat_count': '2', | |
60 'max_time_minutes': '5', | |
61 'bug_id': '425582', | |
62 'gs_bucket': 'chrome-perf', | |
63 'builder_host': 'master4.golo.chromium.org', | |
64 'builder_port': '8341', | |
65 'dummy_builds': True, | |
66 } | |
67 self.dummy_api = mock.MagicMock() | |
68 self.dummy_api.internal_bisect = False | |
69 | |
70 def test_improvement_direction_default(self): | |
71 # By default, no improvement direction should be set | |
72 bisector = auto_bisect.bisector.Bisector(self.dummy_api, self.bisect_config, | |
73 MockRevisionClass) | |
74 self.assertIsNone(bisector.improvement_direction) | |
75 | |
76 def test_improvement_direction_greater_is_better_fail(self): | |
77 # Improvement up, bad > good: should fail | |
78 self.bisect_config['improvement_direction'] = 1 | |
79 bisector = auto_bisect.bisector.Bisector(self.dummy_api, self.bisect_config, | |
80 MockRevisionClass) | |
81 bisector.good_rev.mean_value = 10 | |
82 bisector.bad_rev.mean_value = 100 | |
83 self.assertFalse(bisector.check_improvement_direction()) | |
84 self.assertIn('direction of improvement', ''.join(bisector.warnings)) | |
85 | |
86 def test_improvement_direction_greater_is_better_pass(self): | |
87 # Improvement up, bad < good: should not fail | |
88 self.bisect_config['improvement_direction'] = 1 | |
89 bisector = auto_bisect.bisector.Bisector(self.dummy_api, self.bisect_config, | |
90 MockRevisionClass) | |
91 bisector.good_rev.mean_value = 100 | |
92 bisector.bad_rev.mean_value = 10 | |
93 self.assertTrue(bisector.check_improvement_direction()) | |
94 self.assertNotIn('direction of improvement', ''.join(bisector.warnings)) | |
95 | |
96 def test_improvement_direction_lower_is_better_fail(self): | |
97 # Improvement down, bad < good: should fail | |
98 self.bisect_config['improvement_direction'] = -1 | |
99 bisector = auto_bisect.bisector.Bisector(self.dummy_api, self.bisect_config, | |
100 MockRevisionClass) | |
101 bisector.good_rev.mean_value = 100 | |
102 bisector.bad_rev.mean_value = 10 | |
103 self.assertFalse(bisector.check_improvement_direction()) | |
104 self.assertIn('direction of improvement', ''.join(bisector.warnings)) | |
105 | |
106 def test_improvement_direction_lower_is_better_pass(self): | |
107 # Improvement down, bad > good: should not fail | |
108 self.bisect_config['improvement_direction'] = -1 | |
109 bisector = auto_bisect.bisector.Bisector(self.dummy_api, self.bisect_config, | |
110 MockRevisionClass) | |
111 bisector.good_rev.mean_value = 10 | |
112 bisector.bad_rev.mean_value = 100 | |
113 self.assertTrue(bisector.check_improvement_direction()) | |
114 self.assertNotIn('direction of improvement', ''.join(bisector.warnings)) | |
115 | |
116 def test_improvement_direction_return_code(self): | |
117 # The improvement direction check doesn't apply for return code bisects. | |
118 bisect_config = copy.deepcopy(self.bisect_config) | |
119 bisect_config['test_type'] = 'return_code' | |
120 bisector = auto_bisect.bisector.Bisector(self.dummy_api, bisect_config, | |
121 MockRevisionClass) | |
122 bisector.good_rev.mean_value = 1 | |
123 bisector.bad_rev.mean_value = 0 | |
124 self.assertTrue(bisector.is_return_code_mode()) | |
125 self.assertTrue(bisector.check_improvement_direction()) | |
126 | |
127 @mock.patch.object(auto_bisect.bisector.Bisector, 'significantly_different', | |
128 mock.MagicMock(return_value=True)) | |
129 def test_check_initial_confidence_pass(self): | |
130 # patch bisector.significantly_different with true | |
131 # assert both revisions have > 5 samples | |
132 bisector = auto_bisect.bisector.Bisector(self.dummy_api, self.bisect_config, | |
133 MockRevisionClass) | |
134 bisector.good_rev.values = [3, 3, 3, 3, 3, 3] | |
135 bisector.bad_rev.values = [3, 3, 3, 3] | |
136 self.assertTrue(bisector.check_initial_confidence()) | |
137 self.assertTrue(len(bisector.bad_rev.values) >= 5) | |
138 | |
139 @mock.patch.object(auto_bisect.bisector.Bisector, 'significantly_different', | |
140 mock.MagicMock(return_value=False)) | |
141 def test_check_initial_confidence_non_diverging(self): | |
142 bisector = auto_bisect.bisector.Bisector(self.dummy_api, self.bisect_config, | |
143 MockRevisionClass) | |
144 bisector.good_rev.values = [3, 3, 3, 3, 3, 3] | |
145 bisector.bad_rev.values = [3, 3, 3, 3] | |
146 self.assertFalse(bisector.check_initial_confidence()) | |
147 self.assertTrue(len(bisector.bad_rev.values) >= | |
148 auto_bisect.bisector.MAX_REQUIRED_SAMPLES or | |
149 len(bisector.good_rev.values) >= | |
150 auto_bisect.bisector.MAX_REQUIRED_SAMPLES) | |
151 | |
152 def test_check_initial_confidence_return_code_pass(self): | |
153 return_code_config = self.bisect_config | |
154 return_code_config['test_type'] = 'return_code' | |
155 bisector = auto_bisect.bisector.Bisector(self.dummy_api, return_code_config, | |
156 MockRevisionClass) | |
157 bisector.good_rev.overall_return_code = 0 | |
158 bisector.bad_rev.overall_return_code = 1 | |
159 self.assertTrue(bisector.check_initial_confidence()) | |
160 | |
161 def test_check_initial_confidence_return_code_fail(self): | |
162 return_code_config = self.bisect_config | |
163 return_code_config['test_type'] = 'return_code' | |
164 bisector = auto_bisect.bisector.Bisector(self.dummy_api, return_code_config, | |
165 MockRevisionClass) | |
166 bisector.good_rev.overall_return_code = 0 | |
167 bisector.bad_rev.overall_return_code = 0 | |
168 self.assertFalse(bisector.check_initial_confidence()) | |
169 | |
170 bisector.good_rev.overall_return_code = 1 | |
171 bisector.bad_rev.overall_return_code = 1 | |
172 self.assertFalse(bisector.check_initial_confidence()) | |
173 | |
174 def test_commit_log_from_gitiles(self): | |
175 self.dummy_api.internal_bisect = True | |
176 commits = [ | |
177 {'commit': 'def05678def05678def05678def05678def05678'}, # bad revision | |
178 {'commit': 'bbbbb'}, | |
179 {'commit': 'ccccc'}, | |
180 ] | |
181 self.dummy_api.m.gitiles.log = mock.MagicMock(return_value=(commits, None)) | |
182 auto_bisect.depot_config.DEPOT_DEPS_NAME['android-chrome'] = { | |
183 'src' : 'src/internal', | |
184 'recurse' : True, | |
185 'depends' : None, | |
186 'from' : [], | |
187 'deps_file': '.DEPS.git', | |
188 'url': 'https://dummy-internal-url' | |
189 } | |
190 bisector = auto_bisect.bisector.Bisector( | |
191 self.dummy_api, self.bisect_config, MockRevisionClass) | |
192 for r in bisector.revisions: | |
193 self.assertIn(r.commit_hash, | |
194 [bisector.good_rev.commit_hash, | |
195 'bbbbb', | |
196 'ccccc', | |
197 bisector.bad_rev.commit_hash]) | |
198 | |
199 if __name__ == '__main__': | |
200 unittest.main() # pragma: no cover | |
OLD | NEW |