binary_search_tool_tester.py revision a8af9a7a2462b00e72deff99327bdb452a715277
1#!/usr/bin/python2 2 3# Copyright 2012 Google Inc. All Rights Reserved. 4"""Tests for bisecting tool.""" 5 6from __future__ import print_function 7 8__author__ = 'shenhan@google.com (Han Shen)' 9 10import os 11import random 12import sys 13import unittest 14 15from cros_utils import command_executer 16from binary_search_tool import binary_search_state 17from binary_search_tool import bisect 18 19import common 20import gen_obj 21 22 23def GenObj(): 24 obj_num = random.randint(100, 1000) 25 bad_obj_num = random.randint(obj_num / 100, obj_num / 20) 26 if bad_obj_num == 0: 27 bad_obj_num = 1 28 gen_obj.Main(['--obj_num', str(obj_num), '--bad_obj_num', str(bad_obj_num)]) 29 30 31def CleanObj(): 32 os.remove(common.OBJECTS_FILE) 33 os.remove(common.WORKING_SET_FILE) 34 print('Deleted "{0}" and "{1}"'.format(common.OBJECTS_FILE, 35 common.WORKING_SET_FILE)) 36 37 38class BisectTest(unittest.TestCase): 39 """Tests for bisect.py""" 40 41 def setUp(self): 42 with open('./installed', 'w'): 43 pass 44 45 try: 46 os.remove(binary_search_state.STATE_FILE) 47 except OSError: 48 pass 49 50 def tearDown(self): 51 try: 52 os.remove('./installed') 53 os.remove(os.readlink(binary_search_state.STATE_FILE)) 54 os.remove(binary_search_state.STATE_FILE) 55 except OSError: 56 pass 57 58 class FullBisector(bisect.Bisector): 59 """Test bisector to test bisect.py with""" 60 61 def __init__(self, options, overrides): 62 super(BisectTest.FullBisector, self).__init__(options, overrides) 63 64 def PreRun(self): 65 GenObj() 66 return 0 67 68 def Run(self): 69 return binary_search_state.Run(get_initial_items='./gen_init_list.py', 70 switch_to_good='./switch_to_good.py', 71 switch_to_bad='./switch_to_bad.py', 72 test_script='./is_good.py', 73 prune=True, 74 file_args=True) 75 76 def PostRun(self): 77 CleanObj() 78 return 0 79 80 def test_full_bisector(self): 81 ret = bisect.Run(self.FullBisector({}, {})) 82 self.assertEquals(ret, 0) 83 self.assertFalse(os.path.exists(common.OBJECTS_FILE)) 84 self.assertFalse(os.path.exists(common.WORKING_SET_FILE)) 85 86 def check_output(self): 87 _, out, _ = command_executer.GetCommandExecuter().RunCommandWOutput( 88 ('grep "Bad items are: " logs/binary_search_tool_tester.py.out | ' 89 'tail -n1')) 90 ls = out.splitlines() 91 self.assertEqual(len(ls), 1) 92 line = ls[0] 93 94 _, _, bad_ones = line.partition('Bad items are: ') 95 bad_ones = bad_ones.split() 96 expected_result = common.ReadObjectsFile() 97 98 # Reconstruct objects file from bad_ones and compare 99 actual_result = [0] * len(expected_result) 100 for bad_obj in bad_ones: 101 actual_result[int(bad_obj)] = 1 102 103 self.assertEqual(actual_result, expected_result) 104 105 106class BisectingUtilsTest(unittest.TestCase): 107 """Tests for bisecting tool.""" 108 109 def setUp(self): 110 """Generate [100-1000] object files, and 1-5% of which are bad ones.""" 111 GenObj() 112 113 with open('./installed', 'w'): 114 pass 115 116 try: 117 os.remove(binary_search_state.STATE_FILE) 118 except OSError: 119 pass 120 121 def tearDown(self): 122 """Cleanup temp files.""" 123 CleanObj() 124 125 try: 126 os.remove('./installed') 127 os.remove(os.readlink(binary_search_state.STATE_FILE)) 128 os.remove(binary_search_state.STATE_FILE) 129 except OSError: 130 pass 131 132 def runTest(self): 133 ret = binary_search_state.Run(get_initial_items='./gen_init_list.py', 134 switch_to_good='./switch_to_good.py', 135 switch_to_bad='./switch_to_bad.py', 136 test_script='./is_good.py', 137 prune=True, 138 file_args=True) 139 self.assertEquals(ret, 0) 140 self.check_output() 141 142 def test_arg_parse(self): 143 args = ['--get_initial_items', './gen_init_list.py', '--switch_to_good', 144 './switch_to_good.py', '--switch_to_bad', './switch_to_bad.py', 145 '--test_script', './is_good.py', '--prune', '--file_args'] 146 ret = binary_search_state.Main(args) 147 self.assertEquals(ret, 0) 148 self.check_output() 149 150 def test_install_script(self): 151 os.remove('./installed') 152 with self.assertRaises(AssertionError): 153 ret = binary_search_state.Run(get_initial_items='./gen_init_list.py', 154 switch_to_good='./switch_to_good.py', 155 switch_to_bad='./switch_to_bad.py', 156 test_script='./is_good.py', 157 prune=True, 158 file_args=True) 159 160 ret = binary_search_state.Run(get_initial_items='./gen_init_list.py', 161 switch_to_good='./switch_to_good.py', 162 switch_to_bad='./switch_to_bad.py', 163 test_script='./is_good.py', 164 install_script='./install.py', 165 prune=True, 166 file_args=True) 167 self.assertEquals(ret, 0) 168 self.check_output() 169 170 def test_bad_install_script(self): 171 with self.assertRaises(AssertionError): 172 binary_search_state.Run(get_initial_items='./gen_init_list.py', 173 switch_to_good='./switch_to_good.py', 174 switch_to_bad='./switch_to_bad.py', 175 test_script='./is_good.py', 176 install_script='./install_bad.py', 177 prune=True, 178 file_args=True) 179 180 def test_bad_save_state(self): 181 state_file = binary_search_state.STATE_FILE 182 hidden_state_file = os.path.basename(binary_search_state.HIDDEN_STATE_FILE) 183 184 with open(state_file, 'w') as f: 185 f.write('test123') 186 187 bss = binary_search_state.MockBinarySearchState() 188 with self.assertRaises(binary_search_state.Error): 189 bss.SaveState() 190 191 with open(state_file, 'r') as f: 192 self.assertEquals(f.read(), 'test123') 193 194 os.remove(state_file) 195 196 # Cleanup generated save state that has no symlink 197 files = os.listdir(os.getcwd()) 198 save_states = [x for x in files if x.startswith(hidden_state_file)] 199 _ = [os.remove(x) for x in save_states] 200 201 def test_save_state(self): 202 state_file = binary_search_state.STATE_FILE 203 204 bss = binary_search_state.MockBinarySearchState() 205 bss.SaveState() 206 self.assertTrue(os.path.exists(state_file)) 207 first_state = os.readlink(state_file) 208 209 bss.SaveState() 210 second_state = os.readlink(state_file) 211 self.assertTrue(os.path.exists(state_file)) 212 self.assertTrue(second_state != first_state) 213 self.assertFalse(os.path.exists(first_state)) 214 215 bss.RemoveState() 216 self.assertFalse(os.path.islink(state_file)) 217 self.assertFalse(os.path.exists(second_state)) 218 219 def test_load_state(self): 220 test_items = [1, 2, 3, 4, 5] 221 222 bss = binary_search_state.MockBinarySearchState() 223 bss.all_items = test_items 224 bss.SaveState() 225 226 bss = None 227 228 bss2 = binary_search_state.MockBinarySearchState.LoadState() 229 self.assertEquals(bss2.all_items, test_items) 230 231 def test_tmp_cleanup(self): 232 bss = binary_search_state.MockBinarySearchState( 233 get_initial_items='echo "0\n1\n2\n3"', 234 switch_to_good='./switch_tmp.py', 235 file_args=True) 236 bss.SwitchToGood(['0', '1', '2', '3']) 237 238 tmp_file = None 239 with open('tmp_file', 'r') as f: 240 tmp_file = f.read() 241 os.remove('tmp_file') 242 243 self.assertFalse(os.path.exists(tmp_file)) 244 ws = common.ReadWorkingSet() 245 for i in range(3): 246 self.assertEquals(ws[i], 42) 247 248 def test_verify_fail(self): 249 bss = binary_search_state.MockBinarySearchState( 250 get_initial_items='./gen_init_list.py', 251 switch_to_good='./switch_to_bad.py', 252 switch_to_bad='./switch_to_good.py', 253 test_script='./is_good.py', 254 prune=True, 255 file_args=True, 256 verify_level=1) 257 with self.assertRaises(AssertionError): 258 bss.DoVerify() 259 260 def test_early_terminate(self): 261 bss = binary_search_state.MockBinarySearchState( 262 get_initial_items='./gen_init_list.py', 263 switch_to_good='./switch_to_good.py', 264 switch_to_bad='./switch_to_bad.py', 265 test_script='./is_good.py', 266 prune=True, 267 file_args=True, 268 iterations=1) 269 bss.DoSearch() 270 self.assertFalse(bss.found_items) 271 272 def test_no_prune(self): 273 bss = binary_search_state.MockBinarySearchState( 274 get_initial_items='./gen_init_list.py', 275 switch_to_good='./switch_to_good.py', 276 switch_to_bad='./switch_to_bad.py', 277 test_script='./is_good.py', 278 install_script='./install.py', 279 prune=False, 280 file_args=True) 281 bss.DoSearch() 282 self.assertEquals(len(bss.found_items), 1) 283 284 bad_objs = common.ReadObjectsFile() 285 found_obj = int(bss.found_items.pop()) 286 self.assertEquals(bad_objs[found_obj], 1) 287 288 def check_output(self): 289 _, out, _ = command_executer.GetCommandExecuter().RunCommandWOutput( 290 ('grep "Bad items are: " logs/binary_search_tool_tester.py.out | ' 291 'tail -n1')) 292 ls = out.splitlines() 293 self.assertEqual(len(ls), 1) 294 line = ls[0] 295 296 _, _, bad_ones = line.partition('Bad items are: ') 297 bad_ones = bad_ones.split() 298 expected_result = common.ReadObjectsFile() 299 300 # Reconstruct objects file from bad_ones and compare 301 actual_result = [0] * len(expected_result) 302 for bad_obj in bad_ones: 303 actual_result[int(bad_obj)] = 1 304 305 self.assertEqual(actual_result, expected_result) 306 307 308def Main(argv): 309 num_tests = 2 310 if len(argv) > 1: 311 num_tests = int(argv[1]) 312 313 suite = unittest.TestSuite() 314 for _ in range(0, num_tests): 315 suite.addTest(BisectingUtilsTest()) 316 suite.addTest(BisectingUtilsTest('test_arg_parse')) 317 suite.addTest(BisectingUtilsTest('test_install_script')) 318 suite.addTest(BisectingUtilsTest('test_bad_install_script')) 319 suite.addTest(BisectingUtilsTest('test_bad_save_state')) 320 suite.addTest(BisectingUtilsTest('test_save_state')) 321 suite.addTest(BisectingUtilsTest('test_load_state')) 322 suite.addTest(BisectingUtilsTest('test_tmp_cleanup')) 323 suite.addTest(BisectingUtilsTest('test_verify_fail')) 324 suite.addTest(BisectingUtilsTest('test_early_terminate')) 325 suite.addTest(BisectingUtilsTest('test_no_prune')) 326 suite.addTest(BisectTest('test_full_bisector')) 327 runner = unittest.TextTestRunner() 328 runner.run(suite) 329 330 331if __name__ == '__main__': 332 Main(sys.argv) 333