| 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 |