binary_search_tool_tester.py revision 61ace4c75764cbab29bc0bcddf40d6c2d71996a6
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 utils import command_executer
16from binary_search_tool import binary_search_state
17
18import common
19import gen_obj
20
21
22class BisectingUtilsTest(unittest.TestCase):
23  """Tests for bisecting tool."""
24
25  def setUp(self):
26    """Generate [100-1000] object files, and 1-5% of which are bad ones."""
27    obj_num = random.randint(100, 1000)
28    bad_obj_num = random.randint(obj_num / 100, obj_num / 20)
29    if bad_obj_num == 0:
30      bad_obj_num = 1
31    gen_obj.Main(['--obj_num', str(obj_num), '--bad_obj_num', str(bad_obj_num)])
32
33    with open('./installed', 'w'):
34      pass
35
36    try:
37      os.remove(binary_search_state.STATE_FILE)
38    except OSError:
39      pass
40
41  def tearDown(self):
42    """Cleanup temp files."""
43    os.remove(common.OBJECTS_FILE)
44    os.remove(common.WORKING_SET_FILE)
45    print('Deleted "{0}" and "{1}"'.format(common.OBJECTS_FILE,
46                                           common.WORKING_SET_FILE))
47    try:
48      os.remove('./installed')
49      os.remove(os.readlink(binary_search_state.STATE_FILE))
50      os.remove(binary_search_state.STATE_FILE)
51    except OSError:
52      pass
53
54  def runTest(self):
55    ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
56                                  switch_to_good='./switch_to_good.py',
57                                  switch_to_bad='./switch_to_bad.py',
58                                  test_script='./is_good.py',
59                                  prune=True,
60                                  file_args=True)
61    self.assertEquals(ret, 0)
62    self.check_output()
63
64  def test_arg_parse(self):
65    args = ['--get_initial_items', './gen_init_list.py', '--switch_to_good',
66            './switch_to_good.py', '--switch_to_bad', './switch_to_bad.py',
67            '--test_script', './is_good.py', '--prune', '--file_args']
68    ret = binary_search_state.Main(args)
69    self.assertEquals(ret, 0)
70    self.check_output()
71
72  def test_install_script(self):
73    os.remove('./installed')
74    with self.assertRaises(AssertionError):
75      ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
76                                    switch_to_good='./switch_to_good.py',
77                                    switch_to_bad='./switch_to_bad.py',
78                                    test_script='./is_good.py',
79                                    prune=True,
80                                    file_args=True)
81
82    ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
83                                  switch_to_good='./switch_to_good.py',
84                                  switch_to_bad='./switch_to_bad.py',
85                                  test_script='./is_good.py',
86                                  install_script='./install.py',
87                                  prune=True,
88                                  file_args=True)
89    self.assertEquals(ret, 0)
90    self.check_output()
91
92  def test_bad_install_script(self):
93    with self.assertRaises(AssertionError):
94      binary_search_state.Run(get_initial_items='./gen_init_list.py',
95                              switch_to_good='./switch_to_good.py',
96                              switch_to_bad='./switch_to_bad.py',
97                              test_script='./is_good.py',
98                              install_script='./install_bad.py',
99                              prune=True,
100                              file_args=True)
101
102  def test_bad_save_state(self):
103    state_file = binary_search_state.STATE_FILE
104    hidden_state_file = os.path.basename(binary_search_state.HIDDEN_STATE_FILE)
105
106    with open(state_file, 'w') as f:
107      f.write('test123')
108
109    bss = binary_search_state.MockBinarySearchState()
110    with self.assertRaises(binary_search_state.Error):
111      bss.SaveState()
112
113    with open(state_file, 'r') as f:
114      self.assertEquals(f.read(), 'test123')
115
116    os.remove(state_file)
117
118    # Cleanup generated save state that has no symlink
119    files = os.listdir(os.getcwd())
120    save_states = [x for x in files if x.startswith(hidden_state_file)]
121    _ = [os.remove(x) for x in save_states]
122
123  def test_save_state(self):
124    state_file = binary_search_state.STATE_FILE
125
126    bss = binary_search_state.MockBinarySearchState()
127    bss.SaveState()
128    self.assertTrue(os.path.exists(state_file))
129    first_state = os.readlink(state_file)
130
131    bss.SaveState()
132    second_state = os.readlink(state_file)
133    self.assertTrue(os.path.exists(state_file))
134    self.assertTrue(second_state != first_state)
135    self.assertFalse(os.path.exists(first_state))
136
137    bss.RemoveState()
138    self.assertFalse(os.path.islink(state_file))
139    self.assertFalse(os.path.exists(second_state))
140
141  def test_load_state(self):
142    test_items = [1, 2, 3, 4, 5]
143
144    bss = binary_search_state.MockBinarySearchState()
145    bss.all_items = test_items
146    bss.SaveState()
147
148    bss = None
149
150    bss2 = binary_search_state.MockBinarySearchState.LoadState()
151    self.assertEquals(bss2.all_items, test_items)
152
153  def test_tmp_cleanup(self):
154    bss = binary_search_state.MockBinarySearchState(
155        get_initial_items='echo "0\n1\n2\n3"',
156        switch_to_good='./switch_tmp.py',
157        file_args=True)
158    bss.SwitchToGood(['0', '1', '2', '3'])
159
160    tmp_file = None
161    with open('tmp_file', 'r') as f:
162      tmp_file = f.read()
163    os.remove('tmp_file')
164
165    self.assertFalse(os.path.exists(tmp_file))
166    ws = common.ReadWorkingSet()
167    for i in range(3):
168      self.assertEquals(ws[i], 42)
169
170  def check_output(self):
171    _, out, _ = command_executer.GetCommandExecuter().RunCommandWOutput(
172        ('grep "Bad items are: " logs/binary_search_tool_tester.py.out | '
173         'tail -n1'))
174    ls = out.splitlines()
175    self.assertEqual(len(ls), 1)
176    line = ls[0]
177
178    _, _, bad_ones = line.partition('Bad items are: ')
179    bad_ones = bad_ones.split()
180    expected_result = common.ReadObjectsFile()
181
182    # Reconstruct objects file from bad_ones and compare
183    actual_result = [0] * len(expected_result)
184    for bad_obj in bad_ones:
185      actual_result[int(bad_obj)] = 1
186
187    self.assertEqual(actual_result, expected_result)
188
189
190def Main(argv):
191  num_tests = 2
192  if len(argv) > 1:
193    num_tests = int(argv[1])
194
195  suite = unittest.TestSuite()
196  for _ in range(0, num_tests):
197    suite.addTest(BisectingUtilsTest())
198  suite.addTest(BisectingUtilsTest('test_arg_parse'))
199  suite.addTest(BisectingUtilsTest('test_install_script'))
200  suite.addTest(BisectingUtilsTest('test_bad_install_script'))
201  suite.addTest(BisectingUtilsTest('test_bad_save_state'))
202  suite.addTest(BisectingUtilsTest('test_save_state'))
203  suite.addTest(BisectingUtilsTest('test_load_state'))
204  suite.addTest(BisectingUtilsTest('test_tmp_cleanup'))
205  runner = unittest.TextTestRunner()
206  runner.run(suite)
207
208
209if __name__ == '__main__':
210  Main(sys.argv)
211