aboutsummaryrefslogtreecommitdiff
path: root/binary_search_tool
diff options
context:
space:
mode:
Diffstat (limited to 'binary_search_tool')
-rw-r--r--binary_search_tool/README.testing80
-rwxr-xr-xbinary_search_tool/binary_search_perforce.py22
-rwxr-xr-xbinary_search_tool/binary_search_state.py6
-rwxr-xr-xbinary_search_tool/bisect.py8
-rwxr-xr-xbinary_search_tool/common/interactive_test_noping.sh27
-rwxr-xr-xbinary_search_tool/compiler_wrapper.py2
-rwxr-xr-xbinary_search_tool/cros_pkg/create_cleanup_script.py6
l---------binary_search_tool/cros_pkg/interactive_test_noping.sh1
-rwxr-xr-xbinary_search_tool/cros_pkg/test_setup_usb.sh56
-rw-r--r--binary_search_tool/full_bisect_test/bad-objects-permanent/_LIST7
-rw-r--r--binary_search_tool/full_bisect_test/bad-output-1.txt11
-rw-r--r--binary_search_tool/full_bisect_test/bad-output-2.txt11
-rw-r--r--binary_search_tool/full_bisect_test/bad-output-3.txt11
-rw-r--r--binary_search_tool/full_bisect_test/bin-trees.h29
-rw-r--r--binary_search_tool/full_bisect_test/build.c23
-rwxr-xr-xbinary_search_tool/full_bisect_test/build.sh22
-rwxr-xr-xbinary_search_tool/full_bisect_test/chromeos_build.sh21
-rwxr-xr-xbinary_search_tool/full_bisect_test/cleanup.sh8
-rwxr-xr-xbinary_search_tool/full_bisect_test/get_initial_items.sh9
-rw-r--r--binary_search_tool/full_bisect_test/good-objects-permanent/_LIST7
-rw-r--r--binary_search_tool/full_bisect_test/good-output.txt11
-rw-r--r--binary_search_tool/full_bisect_test/inorder.c22
-rw-r--r--binary_search_tool/full_bisect_test/inorder_norecurse.c.bad42
-rw-r--r--binary_search_tool/full_bisect_test/inorder_norecurse.c.good42
-rwxr-xr-xbinary_search_tool/full_bisect_test/interactive_test.sh56
-rwxr-xr-xbinary_search_tool/full_bisect_test/main-bisect-test.sh104
-rw-r--r--binary_search_tool/full_bisect_test/main.c30
-rwxr-xr-xbinary_search_tool/full_bisect_test/make_sources_bad.sh15
-rwxr-xr-xbinary_search_tool/full_bisect_test/make_sources_good.sh15
-rw-r--r--binary_search_tool/full_bisect_test/preorder.c23
-rw-r--r--binary_search_tool/full_bisect_test/preorder_norecurse.c.bad29
-rw-r--r--binary_search_tool/full_bisect_test/preorder_norecurse.c.good31
-rwxr-xr-xbinary_search_tool/full_bisect_test/run-test-nowrapper.sh68
-rwxr-xr-xbinary_search_tool/full_bisect_test/setup.sh36
-rw-r--r--binary_search_tool/full_bisect_test/stack.c25
-rwxr-xr-xbinary_search_tool/full_bisect_test/switch_to_bad.sh54
-rwxr-xr-xbinary_search_tool/full_bisect_test/switch_to_good.sh57
-rwxr-xr-xbinary_search_tool/full_bisect_test/test_setup.sh16
-rwxr-xr-xbinary_search_tool/run_bisect_test.py172
-rwxr-xr-xbinary_search_tool/sysroot_wrapper/testing_test.py8
-rwxr-xr-xbinary_search_tool/test/binary_search_tool_tester.py132
-rwxr-xr-xbinary_search_tool/test/common.py2
-rwxr-xr-xbinary_search_tool/test/gen_init_list.py2
-rwxr-xr-xbinary_search_tool/test/gen_obj.py6
-rwxr-xr-xbinary_search_tool/test/is_good.py2
-rwxr-xr-xbinary_search_tool/test/is_good_noinc_prune.py2
-rwxr-xr-xbinary_search_tool/test/switch_tmp.py2
-rwxr-xr-xbinary_search_tool/test/switch_to_bad.py2
-rwxr-xr-xbinary_search_tool/test/switch_to_bad_noinc_prune.py2
-rwxr-xr-xbinary_search_tool/test/switch_to_bad_set_file.py2
-rwxr-xr-xbinary_search_tool/test/switch_to_good.py2
-rwxr-xr-xbinary_search_tool/test/switch_to_good_noinc_prune.py2
-rwxr-xr-xbinary_search_tool/test/switch_to_good_set_file.py2
-rwxr-xr-xbinary_search_tool/test/test_setup.py2
-rwxr-xr-xbinary_search_tool/test/test_setup_bad.py2
55 files changed, 1286 insertions, 101 deletions
diff --git a/binary_search_tool/README.testing b/binary_search_tool/README.testing
new file mode 100644
index 00000000..6c81ab96
--- /dev/null
+++ b/binary_search_tool/README.testing
@@ -0,0 +1,80 @@
+This file explains how to set up and run the various kinds of bisection tests.
+
+The bisection tool comes with several sets of tests which you should
+run after updating any of the bisection tool scripts OR after updating
+the Android compiler wrapper (to make sure the wrapper will still work
+correctly with bisection).
+
+Before you start.
+----------------
+
+Before you can run the tests, your PYTHONPATH environment variable
+must be correct. This means that it must include both the
+toolchain-utils directory and the binary_search_tool directory. The
+easiest way to set it is:
+
+$ cd toolchain-utils
+$ export PYTHONPATH=`pwd`:${PYTHONPATH}
+$ cd binary_search_tool
+$ export PYTHONPATH=`pwd`:${PYTHONPATH}
+
+
+Running the unittests.
+----------------------
+
+To run the basic unit tests:
+
+$ cd toolchain-utils/binary_search_tool/test
+$ ./binary_search_tool_tester.py
+
+Running the bisection tests, testing the compiler wrapper.
+----------------------------------------------------------
+
+If you want to run the bisection tests, and test the compiler wrapper
+(to make sure the POPULATE_GOOD and POPULATE_BAD stages are still
+working properly) you can do the following.
+
+If you are testing with the ANDROID COMPILER WRAPPER, you need to to some
+preliminary setup:
+
+Set up the compiler wrapper to replace GCC:
+
+ $ cd <android-root/prebuilts/clang/host/linux-x86/clang-368880/bin
+ $ cp clang gcc
+ $ whereis gcc
+ gcc: /usr/bin/gcc /usr/lib/gcc /usr/bin/X11/gcc /usr/share/man/man1/gcc.1.gz
+ $ cd /usr/bin
+ $ ls -l gcc
+ lrwxrwxrwx 1 root root 7 Feb 3 17:00 gcc -> gcc-4.8*
+ $ sudo mv gcc gcc.real
+ $ sudo ln -s <android-root>/prebuilts/clang/host/linux-x86/clang-3688880/bin/gcc gcc
+
+Move to the correct directory, then run the test script:
+
+ $ cd toolchain-utils/binary_search_tool
+ $ ./run_bisect_test.py
+
+
+If you are testing with the CHROMEOS COMPILER WRAPPER, you MUST run the
+tests from INSIDE your CHROOT (but you don't need to do any special setup):
+
+ $ cd <path-to-chromeos-root>
+ $ cros_sdk
+ $ cd ~/trunk/src/third_party/toolchain-utils
+
+ Set up your PYTHONPATH:
+
+ $ export PYTHONPATH=`pwd`:${PYTHONPATH}
+ $ cd binary_search_tool
+ $ export PYTHONPATH=`pwd`:${PYTHONPATH}
+
+ Run the test script:
+
+ $ ./run_bisect_test.py
+
+
+Running the bisection tests, without testing the compiler wrapper.
+------------------------------------------------------------------
+
+$ cd toolchain-utils/binary_search_tool
+$ ./full_bisect_test/run-test-nowrapper.sh
diff --git a/binary_search_tool/binary_search_perforce.py b/binary_search_tool/binary_search_perforce.py
index 7ac2fba6..aaa09eef 100755
--- a/binary_search_tool/binary_search_perforce.py
+++ b/binary_search_tool/binary_search_perforce.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Module of binary serch for perforce."""
from __future__ import print_function
@@ -368,8 +368,8 @@ class P4GCCBinarySearcher(P4BinarySearcher):
self.CleanupCLs()
# Change the revision of only the gcc part of the toolchain.
command = ('cd %s/gcctools/google_vendor_src_branch/gcc '
- '&& g4 revert ...; g4 sync @%s' %
- (self.checkout_dir, current_revision))
+ '&& g4 revert ...; g4 sync @%s' % (self.checkout_dir,
+ current_revision))
self.current_ce.RunCommand(command)
self.HandleBrokenCLs(current_revision)
@@ -402,11 +402,13 @@ def Main(argv):
'-s', '--script', dest='script', help='Script to run for every version.')
options = parser.parse_args(argv)
# First get all revisions
- p4_paths = ['//depot2/gcctools/google_vendor_src_branch/gcc/gcc-4.4.3/...',
- '//depot2/gcctools/google_vendor_src_branch/binutils/'
- 'binutils-2.20.1-mobile/...',
- '//depot2/gcctools/google_vendor_src_branch/'
- 'binutils/binutils-20100303/...']
+ p4_paths = [
+ '//depot2/gcctools/google_vendor_src_branch/gcc/gcc-4.4.3/...',
+ '//depot2/gcctools/google_vendor_src_branch/binutils/'
+ 'binutils-2.20.1-mobile/...',
+ '//depot2/gcctools/google_vendor_src_branch/'
+ 'binutils/binutils-20100303/...'
+ ]
p4gccbs = P4GCCBinarySearcher('perforce2:2666', p4_paths, '')
# Main loop:
@@ -425,8 +427,8 @@ def Main(argv):
ce = command_executer.GetCommandExecuter()
command = '%s %s' % (script, p4gccbs.checkout_dir)
status = ce.RunCommand(command)
- message = ('Revision: %s produced: %d status\n' %
- (current_revision, status))
+ message = ('Revision: %s produced: %d status\n' % (current_revision,
+ status))
logger.GetLogger().LogOutput(message, print_to_console=verbose)
terminated = p4gccbs.SetStatus(status)
num_tries -= 1
diff --git a/binary_search_tool/binary_search_state.py b/binary_search_tool/binary_search_state.py
index a10e90b9..19065252 100755
--- a/binary_search_tool/binary_search_state.py
+++ b/binary_search_tool/binary_search_state.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""The binary search wrapper."""
from __future__ import print_function
@@ -559,8 +559,8 @@ def Run(get_initial_items,
try:
bss.DoSearch()
bss.RemoveState()
- logger.GetLogger().LogOutput('Total execution time: %s' %
- bss.ElapsedTimeString())
+ logger.GetLogger().LogOutput(
+ 'Total execution time: %s' % bss.ElapsedTimeString())
except Error as e:
logger.GetLogger().LogError(e)
return 1
diff --git a/binary_search_tool/bisect.py b/binary_search_tool/bisect.py
index d5a8b710..c7dd5238 100755
--- a/binary_search_tool/bisect.py
+++ b/binary_search_tool/bisect.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""The unified package/object bisecting tool."""
from __future__ import print_function
@@ -193,9 +193,9 @@ class BisectObject(Bisector):
if options.dir:
os.environ['BISECT_DIR'] = options.dir
self.options.dir = os.environ.get('BISECT_DIR', '/tmp/sysroot_bisect')
- self.setup_cmd = ('%s %s %s %s' % (self.sysroot_wrapper_setup,
- self.options.board, self.options.remote,
- self.options.package))
+ self.setup_cmd = ('%s %s %s %s' %
+ (self.sysroot_wrapper_setup, self.options.board,
+ self.options.remote, self.options.package))
self.ArgOverride(self.default_kwargs, overrides)
diff --git a/binary_search_tool/common/interactive_test_noping.sh b/binary_search_tool/common/interactive_test_noping.sh
new file mode 100755
index 00000000..bb01b950
--- /dev/null
+++ b/binary_search_tool/common/interactive_test_noping.sh
@@ -0,0 +1,27 @@
+#!/bin/bash -u
+#
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# This script asks the user if the image is good or not, allowing the user to
+# conduct whatever tests the user wishes, and waiting for a response.
+#
+# This script is intended to be used by binary_search_state.py, as
+# part of the binary search triage on ChromeOS package and object files. It
+# waits for the test setup script to build and install the image, then asks the
+# user if the image is good or not. It should return '0' if the test succeeds
+# (the image is 'good'); '1' if the test fails (the image is 'bad'); and '125'
+# if it could not determine (does not apply in this case).
+#
+
+source common/common.sh
+
+while true; do
+ read -p "Is this a good ChromeOS image?" yn
+ case $yn in
+ [Yy]* ) exit 0;;
+ [Nn]* ) exit 1;;
+ * ) echo "Please answer yes or no.";;
+ esac
+done
+
+exit 125
diff --git a/binary_search_tool/compiler_wrapper.py b/binary_search_tool/compiler_wrapper.py
index 3d6403a2..a6d189b5 100755
--- a/binary_search_tool/compiler_wrapper.py
+++ b/binary_search_tool/compiler_wrapper.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Prototype compiler wrapper.
Only tested with: gcc, g++, clang, clang++
diff --git a/binary_search_tool/cros_pkg/create_cleanup_script.py b/binary_search_tool/cros_pkg/create_cleanup_script.py
index 32a1f160..ed4eab61 100755
--- a/binary_search_tool/cros_pkg/create_cleanup_script.py
+++ b/binary_search_tool/cros_pkg/create_cleanup_script.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
#
# Copyright 2015 Google Inc. All Rights Reserved
"""The script to generate a cleanup script after setup.sh.
@@ -90,8 +90,8 @@ def Main(argv):
if options.renamed_tree:
# Old build tree existed and was a real tree, so it got
# renamed. Move the renamed tree back to the original tree.
- out_file.write('sudo mv /build/%s.save /build/%s\n' %
- (options.board, options.board))
+ out_file.write('sudo mv /build/%s.save /build/%s\n' % (options.board,
+ options.board))
else:
# Old tree existed and was already a soft link. Re-create the
# original soft link.
diff --git a/binary_search_tool/cros_pkg/interactive_test_noping.sh b/binary_search_tool/cros_pkg/interactive_test_noping.sh
new file mode 120000
index 00000000..c76f9404
--- /dev/null
+++ b/binary_search_tool/cros_pkg/interactive_test_noping.sh
@@ -0,0 +1 @@
+../common/interactive_test_noping.sh \ No newline at end of file
diff --git a/binary_search_tool/cros_pkg/test_setup_usb.sh b/binary_search_tool/cros_pkg/test_setup_usb.sh
new file mode 100755
index 00000000..fec66f8e
--- /dev/null
+++ b/binary_search_tool/cros_pkg/test_setup_usb.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+#
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# This is a generic ChromeOS package/image test setup script. It is meant to
+# be used for the package bisection tool, in particular when there is a booting
+# issue with the image, so the image MUST be 'flashed' via USB.
+#
+# This script is intended to be used by binary_search_state.py, as
+# part of the binary search triage on ChromeOS objects and packages. It should
+# return '0' if the setup succeeds; and '1' if the setup fails (the image
+# could not built or be flashed).
+#
+
+export PYTHONUNBUFFERED=1
+
+source common/common.sh
+
+echo "BUILDING IMAGE"
+pushd ~/trunk/src/scripts
+./build_image test --board=${BISECT_BOARD} --noenable_rootfs_verification --noeclean
+build_status=$?
+popd
+
+if [[ ${build_status} -eq 0 ]] ; then
+ echo
+ echo "INSTALLING IMAGE VIA USB (requires some manual intervention)"
+ echo
+ echo "Insert a usb stick into the current machine"
+ echo "Note: The cros flash will take time and doesn't give much output."
+ echo " Be patient. If your usb access light is flashing it's working."
+ sleep 1
+ read -p "Press enter to continue" notused
+
+ cros flash --board=${BISECT_BOARD} --clobber-stateful usb:// ~/trunk/src/build/images/${BISECT_BOARD}/latest/chromiumos_test_image.bin
+
+ echo
+ echo "Flash to usb complete!"
+ echo "Plug the usb into your chromebook and install the image."
+ echo "Refer to the ChromiumOS Developer's Handbook for more details."
+ echo "http://www.chromium.org/chromium-os/developer-guide#TOC-Boot-from-your-USB-disk"
+ while true; do
+ sleep 1
+ read -p "Was the installation of the image successful? " choice
+ case $choice in
+ [Yy]*) exit 0;;
+ [Nn]*) exit 1;;
+ *) echo "Please answer y or n.";;
+ esac
+ done
+else
+ echo "build_image returned a non-zero status: ${build_status}"
+ exit 1
+fi
+
+exit 0
diff --git a/binary_search_tool/full_bisect_test/bad-objects-permanent/_LIST b/binary_search_tool/full_bisect_test/bad-objects-permanent/_LIST
new file mode 100644
index 00000000..07bc1aa9
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/bad-objects-permanent/_LIST
@@ -0,0 +1,7 @@
+build.o
+inorder_norecurse.o
+inorder.o
+main.o
+preorder_norecurse.o
+preorder.o
+stack.o
diff --git a/binary_search_tool/full_bisect_test/bad-output-1.txt b/binary_search_tool/full_bisect_test/bad-output-1.txt
new file mode 100644
index 00000000..dfd0bfc6
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/bad-output-1.txt
@@ -0,0 +1,11 @@
+pre-order traversal, with recursion:
+35 28 20 25 23 26 30 60 70 65 64 68
+
+pre-order traversal, without recursion:
+35 28 20 25 23 26 30 60 70 65 64 68
+
+in-order traversal, with recursion:
+20 23 25 26 28 30 35 60 64 65 68 70
+
+in-order traversal, without recursion:
+28 30 35 60 65 68 70
diff --git a/binary_search_tool/full_bisect_test/bad-output-2.txt b/binary_search_tool/full_bisect_test/bad-output-2.txt
new file mode 100644
index 00000000..e35ebddc
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/bad-output-2.txt
@@ -0,0 +1,11 @@
+pre-order traversal, with recursion:
+35 28 20 25 23 26 30 60 70 65 64 68
+
+pre-order traversal, without recursion:
+35 60 70
+
+in-order traversal, with recursion:
+20 23 25 26 28 30 35 60 64 65 68 70
+
+in-order traversal, without recursion:
+20 23 25 26 28 30 35 60 64 65 68 70
diff --git a/binary_search_tool/full_bisect_test/bad-output-3.txt b/binary_search_tool/full_bisect_test/bad-output-3.txt
new file mode 100644
index 00000000..5f3bfef5
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/bad-output-3.txt
@@ -0,0 +1,11 @@
+pre-order traversal, with recursion:
+35 28 20 25 23 26 30 60 70 65 64 68
+
+pre-order traversal, without recursion:
+35 60 70
+
+in-order traversal, with recursion:
+20 23 25 26 28 30 35 60 64 65 68 70
+
+in-order traversal, without recursion:
+28 30 35 60 65 68 70
diff --git a/binary_search_tool/full_bisect_test/bin-trees.h b/binary_search_tool/full_bisect_test/bin-trees.h
new file mode 100644
index 00000000..1c4fa199
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/bin-trees.h
@@ -0,0 +1,29 @@
+#ifndef _BIN_TREES_H
+#define _BIN_TREES_H
+
+
+struct bin_tree_struct {
+ int data;
+ char c_data;
+ struct bin_tree_struct *left;
+ struct bin_tree_struct *right;
+};
+
+typedef struct bin_tree_struct * tree_ptr;
+
+
+struct stack_struct {
+ tree_ptr data;
+ struct stack_struct *next;
+};
+
+
+void search_tree_insert (tree_ptr *, int);
+void pre_order_traverse (tree_ptr);
+void pre_order_traverse_no_recurse (tree_ptr);
+void in_order_traverse (tree_ptr);
+void in_order_traverse_no_recurse (tree_ptr);
+void push (struct stack_struct **, tree_ptr);
+tree_ptr pop (struct stack_struct **);
+
+#endif /* _BIN_TREES_H */
diff --git a/binary_search_tool/full_bisect_test/build.c b/binary_search_tool/full_bisect_test/build.c
new file mode 100644
index 00000000..ea1c8b49
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/build.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+#include "bin-trees.h"
+
+tree_ptr
+new_node (int value)
+{
+ tree_ptr node = (tree_ptr) malloc (sizeof (tree_ptr));
+ node->data = value;
+ node->left = NULL;
+ node->right = NULL;
+ return node;
+}
+
+void
+search_tree_insert (tree_ptr *root, int value)
+{
+ if (*root == NULL)
+ *root = new_node (value);
+ else if (value < (*root)->data)
+ search_tree_insert (&((*root)->left), value);
+ else if (value > (*root)->data)
+ search_tree_insert (&((*root)->right), value);
+}
diff --git a/binary_search_tool/full_bisect_test/build.sh b/binary_search_tool/full_bisect_test/build.sh
new file mode 100755
index 00000000..9d40fb55
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/build.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# This file compiles all the source files into .o files, then links them to form
+# the test binary, 'bin-trees'. The .o files all go into the 'work' directory.
+# There are 'good' and 'bad' versions of inorder_norecurse and preorder_norecurse
+# (e.g. inorder_norecurse.c.good and inorder_norecurse.c.bad). This script
+# assumes that the desired versions of those files have been copied into
+# inorder_norecurse.c and preorder_norecurse.c. The script files
+# make_sources_good.sh and make_sources_bad.sh are meant to handle this.
+#
+# This script is meant to be run directly in the full_bisect_test directory.
+# Most other scripts assume they are being run from the parent directory.
+
+gcc -c build.c -o work/build.o
+gcc -c preorder.c -o work/preorder.o
+gcc -c inorder.c -o work/inorder.o
+gcc -c main.c -o work/main.o
+gcc -c stack.c -o work/stack.o
+gcc -c preorder_norecurse.c -o work/preorder_norecurse.o
+gcc -c inorder_norecurse.c -o work/inorder_norecurse.o
+gcc -o bin-trees work/main.o work/preorder.o work/inorder.o work/build.o work/preorder_norecurse.o work/inorder_norecurse.o work/stack.o
+
diff --git a/binary_search_tool/full_bisect_test/chromeos_build.sh b/binary_search_tool/full_bisect_test/chromeos_build.sh
new file mode 100755
index 00000000..f072bd07
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/chromeos_build.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# This file compiles all the source files into .o files, then links them to form
+# the test binary, 'bin-trees'. The .o files all go into the 'work' directory.
+# There are 'good' and 'bad' versions of inorder_norecurse and preorder_norecurse
+# (e.g. inorder_norecurse.c.good and inorder_norecurse.c.bad). This script
+# assumes that the desired versions of those files have been copied into
+# inorder_norecurse.c and preorder_norecurse.c. The script files
+# make_sources_good.sh and make_sources_bad.sh are meant to handle this.
+#
+# This script is meant to be run directly in the full_bisect_test directory.
+# Most other scripts assume they are being run from the parent directory.
+
+x86_64-cros-linux-gnu-gcc -c build.c -o work/build.o
+x86_64-cros-linux-gnu-gcc -c preorder.c -o work/preorder.o
+x86_64-cros-linux-gnu-gcc -c inorder.c -o work/inorder.o
+x86_64-cros-linux-gnu-gcc -c main.c -o work/main.o
+x86_64-cros-linux-gnu-gcc -c stack.c -o work/stack.o
+x86_64-cros-linux-gnu-gcc -c preorder_norecurse.c -o work/preorder_norecurse.o
+x86_64-cros-linux-gnu-gcc -c inorder_norecurse.c -o work/inorder_norecurse.o
+x86_64-cros-linux-gnu-gcc -o bin-trees work/main.o work/preorder.o work/inorder.o work/build.o work/preorder_norecurse.o work/inorder_norecurse.o work/stack.o
diff --git a/binary_search_tool/full_bisect_test/cleanup.sh b/binary_search_tool/full_bisect_test/cleanup.sh
new file mode 100755
index 00000000..48b44f30
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/cleanup.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# In keeping with the normal way of doing bisectin, this script is meant to
+# remove files specific to the particular run of the bisector.
+#
+# This file is called from main-bisect-test.sh
+
+rm full_bisect_test/common.sh
diff --git a/binary_search_tool/full_bisect_test/get_initial_items.sh b/binary_search_tool/full_bisect_test/get_initial_items.sh
new file mode 100755
index 00000000..4c4043f1
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/get_initial_items.sh
@@ -0,0 +1,9 @@
+#!/bin/bash -u
+#
+# This is one of the test scripts that needs to be passed to
+# binary_search_state.py.
+
+source full_bisect_test/common.sh
+
+cat ${BISECT_GOOD_BUILD}/_LIST
+
diff --git a/binary_search_tool/full_bisect_test/good-objects-permanent/_LIST b/binary_search_tool/full_bisect_test/good-objects-permanent/_LIST
new file mode 100644
index 00000000..07bc1aa9
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/good-objects-permanent/_LIST
@@ -0,0 +1,7 @@
+build.o
+inorder_norecurse.o
+inorder.o
+main.o
+preorder_norecurse.o
+preorder.o
+stack.o
diff --git a/binary_search_tool/full_bisect_test/good-output.txt b/binary_search_tool/full_bisect_test/good-output.txt
new file mode 100644
index 00000000..4db15eb2
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/good-output.txt
@@ -0,0 +1,11 @@
+pre-order traversal, with recursion:
+35 28 20 25 23 26 30 60 70 65 64 68
+
+pre-order traversal, without recursion:
+35 28 20 25 23 26 30 60 70 65 64 68
+
+in-order traversal, with recursion:
+20 23 25 26 28 30 35 60 64 65 68 70
+
+in-order traversal, without recursion:
+20 23 25 26 28 30 35 60 64 65 68 70
diff --git a/binary_search_tool/full_bisect_test/inorder.c b/binary_search_tool/full_bisect_test/inorder.c
new file mode 100644
index 00000000..ad093f3c
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/inorder.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "bin-trees.h"
+
+static void
+real_inorder (tree_ptr root)
+{
+ if (root == NULL)
+ return;
+
+ real_inorder (root->left);
+ printf ("%d ", root->data);
+ real_inorder (root->right);
+}
+
+void
+in_order_traverse (tree_ptr root)
+{
+ printf ("in-order traversal, with recursion: \n");
+ real_inorder (root);
+ printf ("\n");
+}
diff --git a/binary_search_tool/full_bisect_test/inorder_norecurse.c.bad b/binary_search_tool/full_bisect_test/inorder_norecurse.c.bad
new file mode 100644
index 00000000..27f0bb16
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/inorder_norecurse.c.bad
@@ -0,0 +1,42 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "bin-trees.h"
+
+static void
+real_in_order_traverse_no_recurse (tree_ptr root)
+{
+ struct stack_struct *stack = NULL;
+ tree_ptr current= root;
+ int going_left = 1; /* boolean variable */
+ while (current != NULL)
+ {
+ if ((current->left != NULL) && going_left)
+ {
+ push (&stack, current);
+ current = current->left;
+ }
+
+ printf ("%d ", current->data);
+ if (current->right)
+ {
+ current = current->right;
+ going_left = 1;
+ }
+ else if (stack != NULL)
+ {
+ current = pop(&stack);
+ going_left = 0;
+ }
+ else
+ current = NULL;
+ }
+}
+
+void
+in_order_traverse_no_recurse (tree_ptr root)
+{
+ printf ("in-order traversal, without recursion: \n");
+ real_in_order_traverse_no_recurse (root);
+ printf ("\n");
+ return;
+}
diff --git a/binary_search_tool/full_bisect_test/inorder_norecurse.c.good b/binary_search_tool/full_bisect_test/inorder_norecurse.c.good
new file mode 100644
index 00000000..a03f4818
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/inorder_norecurse.c.good
@@ -0,0 +1,42 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "bin-trees.h"
+
+static void
+real_in_order_traverse_no_recurse (tree_ptr root)
+{
+ struct stack_struct *stack = NULL;
+ tree_ptr current= root;
+ int going_left = 1; /* boolean variable */
+ while (current != NULL)
+ {
+ while ((current->left != NULL) && going_left)
+ {
+ push (&stack, current);
+ current = current->left;
+ }
+
+ printf ("%d ", current->data);
+ if (current->right)
+ {
+ current = current->right;
+ going_left = 1;
+ }
+ else if (stack != NULL)
+ {
+ current = pop(&stack);
+ going_left = 0;
+ }
+ else
+ current = NULL;
+ }
+}
+
+void
+in_order_traverse_no_recurse (tree_ptr root)
+{
+ printf ("in-order traversal, without recursion: \n");
+ real_in_order_traverse_no_recurse (root);
+ printf ("\n");
+ return;
+}
diff --git a/binary_search_tool/full_bisect_test/interactive_test.sh b/binary_search_tool/full_bisect_test/interactive_test.sh
new file mode 100755
index 00000000..064e4ae5
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/interactive_test.sh
@@ -0,0 +1,56 @@
+#!/bin/bash -u
+#
+# This script is one of the required scripts that get passed to
+# binary_search_state.py. It's job is to test the executable that
+# was generated by mixing/matching good & bad object files, and determine
+# whether the resulting binary is good or bad.
+#
+# In this particular case, the generated binary is 'bin-trees'. This
+# script runs the binary, captures its output, and compares the output
+# to a file containg the correct (good) output, and three files containing
+# what the bad output might look like, depending on if one of the two
+# possile bad .o files was used, or if both bad .o files were used.
+#
+# If the output matches the known good output, this returns 0.
+# If the output matches any known bad output, this returns 1.
+# If the output does not match the good or bad outputs, this returns 125.
+#
+
+source full_bisect_test/common.sh
+
+full_bisect_test/bin-trees > full_bisect_test/temp_output.txt
+
+diff full_bisect_test/temp_output.txt full_bisect_test/good-output.txt &> /dev/null
+retval=$?
+
+if [[ ${retval} -eq 0 ]]; then
+ rm -f full_bisect_test/temp_output.txt
+ exit 0
+fi
+
+diff full_bisect_test/temp_output.txt full_bisect_test/bad-output-1.txt &> /dev/null
+retval=$?
+
+if [[ ${retval} -eq 0 ]]; then
+ rm -f full_bisect_test/temp_output.txt
+ exit 1
+else
+ diff full_bisect_test/temp_output.txt full_bisect_test/bad-output-2.txt &> /dev/null
+ retval=$?
+ if [[ ${retval} -eq 0 ]]; then
+ rm -f full_bisect_test/temp_output.txt
+ exit 1
+ else
+ diff full_bisect_test/temp_output.txt full_bisect_test/bad-output-3.txt &> /dev/null
+ retval=$?
+ if [[ ${retval} -eq 0 ]]; then
+ rm -f full_bisect_test/temp_output.txt
+ exit 1
+ fi
+ fi
+fi
+
+rm -f full_bisect_test/temp_output.txt
+exit 125
+
+
diff --git a/binary_search_tool/full_bisect_test/main-bisect-test.sh b/binary_search_tool/full_bisect_test/main-bisect-test.sh
new file mode 100755
index 00000000..af01c19c
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/main-bisect-test.sh
@@ -0,0 +1,104 @@
+#!/bin/bash
+#
+# This script is the heart of the bisection test. It assumes the good-objects
+# and bad-objects directories have been created and populated. It runs three
+# bisection tests:
+# Test 1. use --file_args, and no pruning, which passes the object file list
+# in a file, and stops as soon as it finds the first bad file.
+# Test 2. do not use --file_args, and no pruning. The object files are passed
+# directly on the command line; stop as soon as it finds the first
+# bad file.
+# Test 3. use --file_args and --prune. Pass the object file list in a file
+# and run until it finds ALL the bad files (there are two of them).
+#
+
+SAVE_DIR=`pwd`
+
+DIR=full_bisect_test
+
+# Make sure you are running this script from the parent directory.
+if [[ ! -f "${DIR}/setup.sh" ]] ; then
+ echo "Cannot find ${DIR}/setup.sh. You are running this from the wrong directory."
+ echo "You need to run this from toolchain-utils/binary_search_tool ."
+ exit 1
+fi
+
+# Run Test 1.
+${DIR}/setup.sh
+
+./binary_search_state.py --get_initial_items="${DIR}/get_initial_items.sh" \
+ --switch_to_good="${DIR}/switch_to_good.sh" \
+ --switch_to_bad="${DIR}/switch_to_bad.sh" \
+ --test_setup_script="${DIR}/test_setup.sh" \
+ --test_script="${DIR}/interactive_test.sh" \
+ --file_args &> /tmp/full_bisect_test.log
+
+${DIR}/cleanup.sh
+
+grep "Search complete. First bad version: " /tmp/full_bisect_test.log &> /dev/null
+test_status=$?
+
+if [[ ${test_status} -ne 0 ]] ; then
+ echo "Test 1 FAILED. See /tmp/full_bisect_test.log for details."
+ exit 1
+else
+ echo "Test 1 passed."
+fi
+
+cd ${SAVE_DIR}
+
+# Run Test 2.
+${DIR}/setup.sh
+
+./binary_search_state.py --get_initial_items="${DIR}/get_initial_items.sh" \
+ --switch_to_good="${DIR}/switch_to_good.sh" \
+ --switch_to_bad="${DIR}/switch_to_bad.sh" \
+ --test_setup_script="${DIR}/test_setup.sh" \
+ --test_script="${DIR}/interactive_test.sh" \
+ &> /tmp/full_bisect_test.log
+
+${DIR}/cleanup.sh
+
+grep "Search complete. First bad version: " /tmp/full_bisect_test.log &> /dev/null
+test_status=$?
+
+if [[ ${test_status} -ne 0 ]] ; then
+ echo "Test 2 FAILED. See /tmp/full_bisect_test.log for details."
+ exit 1
+else
+ echo "Test 2 passed."
+fi
+
+cd ${SAVE_DIR}
+
+# Run Test 3.
+${DIR}/setup.sh
+
+./binary_search_state.py --get_initial_items="${DIR}/get_initial_items.sh" \
+ --switch_to_good="${DIR}/switch_to_good.sh" \
+ --switch_to_bad="${DIR}/switch_to_bad.sh" \
+ --test_setup_script="${DIR}/test_setup.sh" \
+ --test_script="${DIR}/interactive_test.sh" \
+ --file_args --prune &> /tmp/full_bisect_test.log
+
+${DIR}/cleanup.sh
+
+grep "Bad items are: " /tmp/full_bisect_test.log | grep inorder_norecurse.o &> /dev/null
+test_status_1=$?
+
+grep "Bad items are: " /tmp/full_bisect_test.log | grep preorder_norecurse.o &> /dev/null
+test_status_2=$?
+
+if [[ ${test_status_1} -ne 0 ]] ; then
+ echo "Test 3 FAILED. See /tmp/full_bisect_test.log for details."
+ exit 1
+elif [[ ${test_status_2} -ne 0 ]] ; then
+ echo "Test 3 FAILED. See /tmp/full_bisect_test.log for details."
+ exit 1
+else
+ echo "Test 3 passed."
+fi
+
+# All tests passed!
+exit 0
+
diff --git a/binary_search_tool/full_bisect_test/main.c b/binary_search_tool/full_bisect_test/main.c
new file mode 100644
index 00000000..55abc44b
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/main.c
@@ -0,0 +1,30 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "bin-trees.h"
+
+int integers[] = {35, 28, 20, 30, 25, 23, 26, 60, 70, 65, 64, 68 };
+
+char pre_order[] = { '/', '-', '+', '*', 'a', '^', 'x', '2', '&', 'b', 'y',
+ 'c', '3' };
+char in_order[] = { 'a', '*', 'x', '^', '2', '+', 'b', '&', 'y', '-', 'c',
+ '/', '3' };
+
+int
+main (int argc, char ** argv)
+{
+ int intlist_size = 12;
+ int i;
+ tree_ptr root = NULL;
+ for (i = 0; i < intlist_size; ++i)
+ {
+ search_tree_insert (&root, integers[i]);
+ }
+ pre_order_traverse (root);
+ printf ("\n");
+ pre_order_traverse_no_recurse (root);
+ printf ("\n");
+ in_order_traverse (root);
+ printf ("\n");
+ in_order_traverse_no_recurse (root);
+ return 0;
+}
diff --git a/binary_search_tool/full_bisect_test/make_sources_bad.sh b/binary_search_tool/full_bisect_test/make_sources_bad.sh
new file mode 100755
index 00000000..507e8ca8
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/make_sources_bad.sh
@@ -0,0 +1,15 @@
+#!/bin/bash -u
+#
+# There are two versions (good & bad) of inorder_norecurse.c and
+# preorder_norecurse.c. This script makes sure the bad versions
+# are copied into the .c files that will be built and copied into
+# the bad-objects directory, for the bisection test. It is called
+# from run-test-nowrapper.sh.
+#
+
+pushd full_bisect_test
+
+cp inorder_norecurse.c.bad inorder_norecurse.c
+cp preorder_norecurse.c.bad preorder_norecurse.c
+
+popd
diff --git a/binary_search_tool/full_bisect_test/make_sources_good.sh b/binary_search_tool/full_bisect_test/make_sources_good.sh
new file mode 100755
index 00000000..611e9442
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/make_sources_good.sh
@@ -0,0 +1,15 @@
+#!/bin/bash -u
+#
+# There are two versions (good & bad) of inorder_norecurse.c and
+# preorder_norecurse.c. This script makes sure the good versions
+# are copied into the .c files that will be built and copied into
+# the good-objects directory, for the bisection test. It is called
+# from run-test-nowrapper.sh.
+#
+
+pushd full_bisect_test
+
+cp inorder_norecurse.c.good inorder_norecurse.c
+cp preorder_norecurse.c.good preorder_norecurse.c
+
+popd
diff --git a/binary_search_tool/full_bisect_test/preorder.c b/binary_search_tool/full_bisect_test/preorder.c
new file mode 100644
index 00000000..11fe93a3
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/preorder.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "bin-trees.h"
+
+static void
+real_preorder (tree_ptr root)
+{
+ if (root == NULL)
+ return;
+
+ printf ("%d ", root->data);
+ real_preorder (root->left);
+ real_preorder (root->right);
+}
+
+
+void
+pre_order_traverse (tree_ptr root)
+{
+ printf ("pre-order traversal, with recursion: \n");
+ real_preorder (root) ;
+ printf ("\n");
+}
diff --git a/binary_search_tool/full_bisect_test/preorder_norecurse.c.bad b/binary_search_tool/full_bisect_test/preorder_norecurse.c.bad
new file mode 100644
index 00000000..a8b4b487
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/preorder_norecurse.c.bad
@@ -0,0 +1,29 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "bin-trees.h"
+
+static void
+real_pre_order_traverse_no_recurse (tree_ptr root)
+{
+ struct stack_struct *stack = NULL;
+
+ if (root != NULL)
+ push (&stack, root);
+
+ while (stack != NULL)
+ {
+ tree_ptr current = pop (&stack);
+ printf ("%d ", current->data);
+ if (current->right != NULL)
+ push (&stack, current->right);
+ }
+ return;
+}
+
+void
+pre_order_traverse_no_recurse (tree_ptr root)
+{
+ printf ("pre-order traversal, without recursion: \n");
+ real_pre_order_traverse_no_recurse (root);
+ printf ("\n");
+}
diff --git a/binary_search_tool/full_bisect_test/preorder_norecurse.c.good b/binary_search_tool/full_bisect_test/preorder_norecurse.c.good
new file mode 100644
index 00000000..98f40913
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/preorder_norecurse.c.good
@@ -0,0 +1,31 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "bin-trees.h"
+
+static void
+real_pre_order_traverse_no_recurse (tree_ptr root)
+{
+ struct stack_struct *stack = NULL;
+
+ if (root != NULL)
+ push (&stack, root);
+
+ while (stack != NULL)
+ {
+ tree_ptr current = pop (&stack);
+ printf ("%d ", current->data);
+ if (current->right != NULL)
+ push (&stack, current->right);
+ if (current->left != NULL)
+ push (&stack, current->left);
+ }
+ return;
+}
+
+void
+pre_order_traverse_no_recurse (tree_ptr root)
+{
+ printf ("pre-order traversal, without recursion: \n");
+ real_pre_order_traverse_no_recurse (root);
+ printf ("\n");
+}
diff --git a/binary_search_tool/full_bisect_test/run-test-nowrapper.sh b/binary_search_tool/full_bisect_test/run-test-nowrapper.sh
new file mode 100755
index 00000000..afc4a446
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/run-test-nowrapper.sh
@@ -0,0 +1,68 @@
+#!/bin/bash
+#
+# This script is one of the two main driver scripts for testing the bisector.
+# It should be used to test the bisection tool, if you do NOT want to test
+# the compiler wrapper (e.g. don't bother with POPULATE_GOOD & POPULATE_BAD
+# stages).
+#
+# It makes sure the good & bad object directories exist (soft links); checks
+# to see if it needs to compile the good & bad sources & populate the
+# directories; does so if needed.
+#
+# Then it calls main-bisect-test, which runs the actual bisection tests. This
+# script assumes it is being run from the parent directory.
+#
+# NOTE: Your PYTHONPATH environment variable needs to include both the
+# toolchain-utils directory and the
+# toolchain-utils/binary_search_tool directory for these testers to work.
+#
+
+SAVE_DIR=`pwd`
+
+DIR=full_bisect_test
+
+if [[ ! -d "${DIR}" ]] ; then
+ echo "Cannot find ${DIR}; you are running this script from the wrong place."
+ echo "You need to run this from toolchain-utils/binary_search_tool ."
+ exit 1
+fi
+
+# Set up object file soft links
+cd ${DIR}
+
+rm -f good-objects
+rm -f bad-objects
+
+ln -s good-objects-permanent good-objects
+ln -s bad-objects-permanent bad-objects
+
+if [[ ! -d work ]] ; then
+ mkdir work
+fi
+
+# Check to see if the object files need to be built.
+if [[ ! -f good-objects-permanent/build.o ]] ; then
+ # 'make clean'
+ rm -f work/*.o
+ # skip populate stages in bisect wrapper
+ unset BISECT_STAGE
+ # Set up the 'good' source files.
+ cd ..
+ ${DIR}/make_sources_good.sh
+ cd ${DIR}
+ # Build the 'good' .o files & copy to appropriate directory.
+ ./build.sh
+ mv work/*.o good-objects-permanent/.
+ # Set up the 'bad' source files.
+ cd ..
+ ${DIR}/make_sources_bad.sh
+ cd ${DIR}
+ # Build the 'bad' .o files & copy to appropriate directory.
+ ./build.sh
+ mv work/*.o bad-objects-permanent/.
+fi
+
+# Now we're ready for the main test.
+
+cd ${SAVE_DIR}
+${DIR}/main-bisect-test.sh
diff --git a/binary_search_tool/full_bisect_test/setup.sh b/binary_search_tool/full_bisect_test/setup.sh
new file mode 100755
index 00000000..1214de92
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/setup.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+#
+# This script creates common.sh, which will be sourced by all the other
+# scripts, to set up the necessary environment variables for the bisection
+# to work properly. It is called from main-bisect-test.sh.
+#
+
+DIR=`pwd`/"full_bisect_test"
+
+GOOD_BUILD=${DIR}/good-objects
+BAD_BUILD=${DIR}/bad-objects
+
+mkdir -p ${DIR}/work
+
+WORK_BUILD=${DIR}/work
+
+rm -f ${WORK_BUILD}/*
+
+COMMON_FILE="${DIR}/common.sh"
+
+cat <<-EOF > ${COMMON_FILE}
+
+BISECT_GOOD_BUILD=${GOOD_BUILD}
+BISECT_BAD_BUILD=${BAD_BUILD}
+BISECT_WORK_BUILD=${WORK_BUILD}
+
+BISECT_GOOD_SET=${GOOD_BUILD}/_LIST
+BISECT_BAD_BAD=${BAD_BUILD}/_LIST
+
+BISECT_STAGE="TRIAGE"
+
+EOF
+
+chmod 755 ${COMMON_FILE}
+
+exit 0
diff --git a/binary_search_tool/full_bisect_test/stack.c b/binary_search_tool/full_bisect_test/stack.c
new file mode 100644
index 00000000..f8d0568f
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/stack.c
@@ -0,0 +1,25 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "bin-trees.h"
+
+tree_ptr
+pop (struct stack_struct **stack)
+{
+ if (*stack == NULL)
+ return NULL;
+ else
+ {
+ tree_ptr value = (*stack)->data;
+ (*stack) = (*stack)->next;
+ return value;
+ }
+}
+
+void
+push (struct stack_struct **stack, tree_ptr value)
+{
+ struct stack_struct *new_node = (struct stack_struct *) malloc (sizeof (struct stack_struct *));
+ new_node->data = value;
+ new_node->next = *stack;
+ *stack = new_node;
+}
diff --git a/binary_search_tool/full_bisect_test/switch_to_bad.sh b/binary_search_tool/full_bisect_test/switch_to_bad.sh
new file mode 100755
index 00000000..d88a4aa2
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/switch_to_bad.sh
@@ -0,0 +1,54 @@
+#!/bin/bash -u
+#
+# This is one of the scripts that is passed to binary_search_state.py to do
+# the bisection. This one takes a list of object files (either a real list or
+# a file containing the list) and copies the files from the bad objects
+# directory to the working directory.
+#
+
+source full_bisect_test/common.sh
+
+pushd ${BISECT_WORK_BUILD}
+chmod 644 *
+
+OBJ_LIST_FILES=$1
+FILE_ARGS=0
+
+if [[ -f ${OBJ_LIST_FILES} ]] ; then
+ file ${OBJ_LIST_FILES} &> ${BISECT_WORK_BUILD}/file_type.tmp
+ grep "ASCII text" ${BISECT_WORK_BUILD}/file_type.tmp
+ result=$?
+ if [[ ${result} -eq 0 ]] ; then
+ FILE_ARGS=1
+ fi
+ rm ${BISECT_WORK_BUILD}/file_type.tmp
+fi
+
+overall_status=0
+
+if [[ ${FILE_ARGS} -eq 1 ]] ; then
+ while read obj || [[ -n "${obj}" ]];
+ do
+ cp ${BISECT_BAD_BUILD}/${obj} ${BISECT_WORK_BUILD}
+ status=$?
+ if [[ ${status} -ne 0 ]] ; then
+ echo "Failed to copy ${obj} to work build tree."
+ overall_status=2
+ fi
+ done < ${OBJ_LIST_FILES}
+else
+
+ for o in "$@"
+ do
+ cp ${BISECT_BAD_BUILD}/${o} ${BISECT_WORK_BUILD}
+ status=$?
+ if [[ ${status} -ne 0 ]] ; then
+ echo "Failed to copy ${o} to work build tree."
+ overall_status=2
+ fi
+ done
+fi
+
+popd
+
+exit ${overall_status}
diff --git a/binary_search_tool/full_bisect_test/switch_to_good.sh b/binary_search_tool/full_bisect_test/switch_to_good.sh
new file mode 100755
index 00000000..9d8c29bc
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/switch_to_good.sh
@@ -0,0 +1,57 @@
+#!/bin/bash -u
+#
+# This is one of the scripts that is passed to binary_search_state.py to do
+# the bisection. This one takes a list of object files (either a real list or
+# a file containing the list) and copies the files from the good objects
+# directory to the working directory.
+#
+
+
+source full_bisect_test/common.sh
+
+pushd ${BISECT_WORK_BUILD}
+chmod 644 *
+
+OBJ_LIST_FILES=$1
+FILE_ARGS=0
+
+if [[ -f ${OBJ_LIST_FILES} ]] ; then
+ file ${OBJ_LIST_FILES} &> ${BISECT_WORK_BUILD}/file_type.tmp
+ grep "ASCII text" ${BISECT_WORK_BUILD}/file_type.tmp
+ result=$?
+ if [[ ${result} -eq 0 ]] ; then
+ FILE_ARGS=1
+ fi
+ rm ${BISECT_WORK_BUILD}/file_type.tmp
+fi
+
+overall_status=0
+
+if [[ ${FILE_ARGS} -eq 1 ]] ; then
+ while read obj || [[ -n "${obj}" ]];
+ do
+ echo "Copying {BISECT_GOOD_BUILD}/${obj} to ${BISECT_WORK_BUILD}"
+ cp ${BISECT_GOOD_BUILD}/${obj} ${BISECT_WORK_BUILD}
+# cp ${obj} ${BISECT_WORK_BUILD}/.
+ status=$?
+ if [[ ${status} -ne 0 ]] ; then
+ echo "Failed to copy ${obj} to work build tree."
+ overall_status=2
+ fi
+ done < ${OBJ_LIST_FILES}
+else
+
+ for o in "$@"
+ do
+ cp ${BISECT_GOOD_BUILD}/${o} ${BISECT_WORK_BUILD}
+ status=$?
+ if [[ ${status} -ne 0 ]] ; then
+ echo "Failed to copy ${o} to work build tree."
+ overall_status=2
+ fi
+ done
+fi
+
+popd
+
+exit ${overall_status}
diff --git a/binary_search_tool/full_bisect_test/test_setup.sh b/binary_search_tool/full_bisect_test/test_setup.sh
new file mode 100755
index 00000000..bb313831
--- /dev/null
+++ b/binary_search_tool/full_bisect_test/test_setup.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This is one of the scripts that gets passed to binary_search_state.py.
+# It's supposed to generate the binary to be tested, from the mix of
+# good & bad object files.
+#
+source full_bisect_test/common.sh
+
+WD=`pwd`
+
+cd full_bisect_test
+
+echo "BUILDING IMAGE"
+
+gcc -o bin-trees work/*.o
+
diff --git a/binary_search_tool/run_bisect_test.py b/binary_search_tool/run_bisect_test.py
new file mode 100755
index 00000000..d4ff4f73
--- /dev/null
+++ b/binary_search_tool/run_bisect_test.py
@@ -0,0 +1,172 @@
+#!/usr/bin/env python2
+"""Run full bisection test."""
+
+from __future__ import print_function
+
+import argparse
+import os
+import sys
+
+from cros_utils import command_executer
+
+TEST_DIR = 'full_bisect_test'
+DEFAULT_BISECT_DIR = '/tmp/sysroot_bisect'
+
+
+def populate_good_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR):
+ # 'make clean'
+ work_dir = os.path.join(top_dir, TEST_DIR, 'work')
+ cmd = 'rm -f %s/*.o' % work_dir
+ status = ce.RunCommand(cmd)
+ if status != 0:
+ print('Error trying to clean out work directory: %s' % cmd)
+ return status
+
+ # set up the 'good' source files
+ script = os.path.join(top_dir, TEST_DIR, 'make_sources_good.sh')
+ status = ce.RunCommand(script)
+ if status != 0:
+ print('Error setting up "good" source files: %s' % script)
+ return status
+
+ export_bisect = 'export BISECT_DIR=%s; ' % bisect_dir
+ # build the good source files
+ script_path = os.path.join(top_dir, TEST_DIR)
+ if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'):
+ build_script = 'chromeos_build.sh'
+ else:
+ build_script = 'build.sh'
+ cmd = ('%s export BISECT_STAGE=POPULATE_GOOD; pushd %s; ./%s; popd' %
+ (export_bisect, script_path, build_script))
+ status = ce.RunCommand(cmd)
+ return status
+
+
+def populate_bad_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR):
+ # 'make clean'
+ work_dir = os.path.join(top_dir, TEST_DIR, 'work')
+ cmd = 'rm -f %s/*.o' % work_dir
+ status = ce.RunCommand(cmd)
+ if status != 0:
+ print('Error trying to clean out work directory: %s' % cmd)
+ return status
+
+ # set up the 'bad' source files
+ script = os.path.join(top_dir, TEST_DIR, 'make_sources_bad.sh')
+ status = ce.RunCommand(script)
+ if status != 0:
+ print('Error setting up "bad" source files: %s' % script)
+ return status
+
+ export_bisect = 'export BISECT_DIR=%s; ' % bisect_dir
+ # build the bad source files
+ script_path = os.path.join(top_dir, TEST_DIR)
+ if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'):
+ build_script = 'chromeos_build.sh'
+ else:
+ build_script = 'build.sh'
+ cmd = ('%s export BISECT_STAGE=POPULATE_BAD; pushd %s; ./%s ; popd' %
+ (export_bisect, script_path, build_script))
+ status = ce.RunCommand(cmd)
+ return status
+
+
+def run_main_bisection_test(top_dir, ce):
+ test_script = os.path.join(top_dir, TEST_DIR, 'main-bisect-test.sh')
+ status = ce.RunCommand(test_script)
+ return status
+
+
+def verify_compiler_and_wrapper():
+ # We don't need to do any special setup if running inside a ChromeOS
+ # chroot.
+ if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'):
+ return
+
+ message = """
+*** IMPORTANT --- READ THIS CAREFULLY!! ***
+
+This test uses the command 'gcc' to compile the good/bad versions of the
+source program. BEFORE you can run this script you must make sure that
+your compiler wrapper is in the right place, with the right name, so that
+a call to 'gcc' will go through your compiler wrapper and "do the right
+thing".
+
+Is your compiler wrapper properly set up? [Y/n]
+"""
+
+ print(message)
+ inp = sys.stdin.readline()
+ inp = inp.strip()
+ inp = inp.lower()
+ return not inp or inp == 'y' or inp == 'yes'
+
+
+def Main(argv):
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--dir',
+ dest='directory',
+ help='Bisection work tree, where good & bad object '
+ 'files go. Default is /tmp/sysroot_bisect')
+
+ options = parser.parse_args(argv)
+
+ # Make sure the compiler wrapper & soft links are properly set up.
+ wrapper_is_setup = verify_compiler_and_wrapper()
+ if not wrapper_is_setup:
+ print('Exiting now. Please re-run after you have set up the compiler '
+ 'wrapper.')
+ return 0
+
+ # Make sure we're in the correct directory for running this test.
+ cwd = os.getcwd()
+ if not os.path.exists(os.path.join(cwd, 'full_bisect_test')):
+ print('Error: Wrong directory. This script must be run from the top level'
+ ' of the binary_search_tool tree (under toolchain_utils).')
+ return 1
+
+ ce = command_executer.GetCommandExecuter()
+ bisect_dir = options.directory
+ if not bisect_dir:
+ bisect_dir = DEFAULT_BISECT_DIR
+
+ # Make sure BISECT_DIR is clean
+ if os.path.exists(bisect_dir):
+ cmd = 'rm -Rf %s/*' % bisect_dir
+ retv = ce.RunCommand(cmd)
+ if retv != 0:
+ return retv
+
+ retv = populate_good_files(cwd, ce, bisect_dir)
+ if retv != 0:
+ return retv
+
+ retv = populate_bad_files(cwd, ce, bisect_dir)
+ if retv != 0:
+ return retv
+
+ # Set up good/bad work soft links
+ cmd = ('rm -f %s/%s/good-objects; ln -s %s/good %s/%s/good-objects' %
+ (cwd, TEST_DIR, bisect_dir, cwd, TEST_DIR))
+
+ status = ce.RunCommand(cmd)
+ if status != 0:
+ print('Error executing: %s; exiting now.' % cmd)
+ return status
+
+ cmd = ('rm -f %s/%s/bad-objects; ln -s %s/bad %s/%s/bad-objects' %
+ (cwd, TEST_DIR, bisect_dir, cwd, TEST_DIR))
+
+ status = ce.RunCommand(cmd)
+ if status != 0:
+ print('Error executing: %s; exiting now.' % cmd)
+ return status
+
+ retv = run_main_bisection_test(cwd, ce)
+ return retv
+
+
+if __name__ == '__main__':
+ retval = Main(sys.argv[1:])
+ sys.exit(retval)
diff --git a/binary_search_tool/sysroot_wrapper/testing_test.py b/binary_search_tool/sysroot_wrapper/testing_test.py
index 2f7bc4c3..a0d6ca10 100755
--- a/binary_search_tool/sysroot_wrapper/testing_test.py
+++ b/binary_search_tool/sysroot_wrapper/testing_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Test for sysroot_wrapper bisector.
All files in bad_files will be determined to be bad. This test was made for
@@ -15,9 +15,9 @@ import os
base_path = ('/var/cache/chromeos-chrome/chrome-src-internal/src/out_daisy/'
'Release/obj/')
bad_files = [
- os.path.join(base_path, 'base/base.cpu.o'),
- os.path.join(base_path, 'base/base.version.o'),
- os.path.join(base_path, 'apps/apps.launcher.o')
+ os.path.join(base_path, 'base/base.cpu.o'), os.path.join(
+ base_path, 'base/base.version.o'), os.path.join(base_path,
+ 'apps/apps.launcher.o')
]
bisect_dir = os.environ.get('BISECT_DIR', '/tmp/sysroot_bisect')
diff --git a/binary_search_tool/test/binary_search_tool_tester.py b/binary_search_tool/test/binary_search_tool_tester.py
index 775c1715..e733d9c4 100755
--- a/binary_search_tool/test/binary_search_tool_tester.py
+++ b/binary_search_tool/test/binary_search_tool_tester.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
# Copyright 2012 Google Inc. All Rights Reserved.
"""Tests for bisecting tool."""
@@ -66,12 +66,13 @@ class BisectTest(unittest.TestCase):
return 0
def Run(self):
- return binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good.py',
- switch_to_bad='./switch_to_bad.py',
- test_script='./is_good.py',
- prune=True,
- file_args=True)
+ return binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good.py',
+ switch_to_bad='./switch_to_bad.py',
+ test_script='./is_good.py',
+ prune=True,
+ file_args=True)
def PostRun(self):
CleanObj()
@@ -127,26 +128,31 @@ class BisectingUtilsTest(unittest.TestCase):
except OSError:
pass
- cleanup_list = ['./is_setup', binary_search_state.STATE_FILE,
- 'noinc_prune_bad', 'noinc_prune_good']
+ cleanup_list = [
+ './is_setup', binary_search_state.STATE_FILE, 'noinc_prune_bad',
+ 'noinc_prune_good'
+ ]
for f in cleanup_list:
if os.path.exists(f):
os.remove(f)
def runTest(self):
- ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good.py',
- switch_to_bad='./switch_to_bad.py',
- test_script='./is_good.py',
- prune=True,
- file_args=True)
+ ret = binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good.py',
+ switch_to_bad='./switch_to_bad.py',
+ test_script='./is_good.py',
+ prune=True,
+ file_args=True)
self.assertEquals(ret, 0)
self.check_output()
def test_arg_parse(self):
- args = ['--get_initial_items', './gen_init_list.py', '--switch_to_good',
- './switch_to_good.py', '--switch_to_bad', './switch_to_bad.py',
- '--test_script', './is_good.py', '--prune', '--file_args']
+ args = [
+ '--get_initial_items', './gen_init_list.py', '--switch_to_good',
+ './switch_to_good.py', '--switch_to_bad', './switch_to_bad.py',
+ '--test_script', './is_good.py', '--prune', '--file_args'
+ ]
ret = binary_search_state.Main(args)
self.assertEquals(ret, 0)
self.check_output()
@@ -154,32 +160,35 @@ class BisectingUtilsTest(unittest.TestCase):
def test_test_setup_script(self):
os.remove('./is_setup')
with self.assertRaises(AssertionError):
- ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good.py',
- switch_to_bad='./switch_to_bad.py',
- test_script='./is_good.py',
- prune=True,
- file_args=True)
-
- ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good.py',
- switch_to_bad='./switch_to_bad.py',
- test_script='./is_good.py',
- test_setup_script='./test_setup.py',
- prune=True,
- file_args=True)
+ ret = binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good.py',
+ switch_to_bad='./switch_to_bad.py',
+ test_script='./is_good.py',
+ prune=True,
+ file_args=True)
+
+ ret = binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good.py',
+ switch_to_bad='./switch_to_bad.py',
+ test_script='./is_good.py',
+ test_setup_script='./test_setup.py',
+ prune=True,
+ file_args=True)
self.assertEquals(ret, 0)
self.check_output()
def test_bad_test_setup_script(self):
with self.assertRaises(AssertionError):
- binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good.py',
- switch_to_bad='./switch_to_bad.py',
- test_script='./is_good.py',
- test_setup_script='./test_setup_bad.py',
- prune=True,
- file_args=True)
+ binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good.py',
+ switch_to_bad='./switch_to_bad.py',
+ test_script='./is_good.py',
+ test_setup_script='./test_setup_bad.py',
+ prune=True,
+ file_args=True)
def test_bad_save_state(self):
state_file = binary_search_state.STATE_FILE
@@ -294,13 +303,14 @@ class BisectingUtilsTest(unittest.TestCase):
self.assertEquals(bad_objs[found_obj], 1)
def test_set_file(self):
- binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good_set_file.py',
- switch_to_bad='./switch_to_bad_set_file.py',
- test_script='./is_good.py',
- prune=True,
- file_args=True,
- verify=True)
+ binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good_set_file.py',
+ switch_to_bad='./switch_to_bad_set_file.py',
+ test_script='./is_good.py',
+ prune=True,
+ file_args=True,
+ verify=True)
self.check_output()
def test_noincremental_prune(self):
@@ -343,13 +353,14 @@ class BisectStressTest(unittest.TestCase):
def test_every_obj_bad(self):
amt = 25
gen_obj.Main(['--obj_num', str(amt), '--bad_obj_num', str(amt)])
- ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good.py',
- switch_to_bad='./switch_to_bad.py',
- test_script='./is_good.py',
- prune=True,
- file_args=True,
- verify=False)
+ ret = binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good.py',
+ switch_to_bad='./switch_to_bad.py',
+ test_script='./is_good.py',
+ prune=True,
+ file_args=True,
+ verify=False)
self.assertEquals(ret, 0)
self.check_output()
@@ -360,13 +371,14 @@ class BisectStressTest(unittest.TestCase):
obj_list[i] = '1'
obj_list = ','.join(obj_list)
gen_obj.Main(['--obj_list', obj_list])
- ret = binary_search_state.Run(get_initial_items='./gen_init_list.py',
- switch_to_good='./switch_to_good.py',
- switch_to_bad='./switch_to_bad.py',
- test_setup_script='./test_setup.py',
- test_script='./is_good.py',
- prune=True,
- file_args=True)
+ ret = binary_search_state.Run(
+ get_initial_items='./gen_init_list.py',
+ switch_to_good='./switch_to_good.py',
+ switch_to_bad='./switch_to_bad.py',
+ test_setup_script='./test_setup.py',
+ test_script='./is_good.py',
+ prune=True,
+ file_args=True)
self.assertEquals(ret, 0)
self.check_output()
diff --git a/binary_search_tool/test/common.py b/binary_search_tool/test/common.py
index baac9434..5c3ff538 100755
--- a/binary_search_tool/test/common.py
+++ b/binary_search_tool/test/common.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Common utility functions."""
DEFAULT_OBJECT_NUMBER = 1238
diff --git a/binary_search_tool/test/gen_init_list.py b/binary_search_tool/test/gen_init_list.py
index 4a79a1b1..002fc352 100755
--- a/binary_search_tool/test/gen_init_list.py
+++ b/binary_search_tool/test/gen_init_list.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Prints out index for every object file, starting from 0."""
from __future__ import print_function
diff --git a/binary_search_tool/test/gen_obj.py b/binary_search_tool/test/gen_obj.py
index 265729d2..d17e93f5 100755
--- a/binary_search_tool/test/gen_obj.py
+++ b/binary_search_tool/test/gen_obj.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Script to generate a list of object files.
0 represents a good object file.
@@ -86,8 +86,8 @@ def Main(argv):
obj_num = len(obj_list)
bad_obj_num = obj_list.count('1')
- print('Generated {0} object files, with {1} bad ones.'.format(obj_num,
- bad_obj_num))
+ print('Generated {0} object files, with {1} bad ones.'.format(
+ obj_num, bad_obj_num))
return 0
diff --git a/binary_search_tool/test/is_good.py b/binary_search_tool/test/is_good.py
index bfe9cc32..a0be4a08 100755
--- a/binary_search_tool/test/is_good.py
+++ b/binary_search_tool/test/is_good.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Check to see if the working set produces a good executable."""
from __future__ import print_function
diff --git a/binary_search_tool/test/is_good_noinc_prune.py b/binary_search_tool/test/is_good_noinc_prune.py
index 5aafd6c2..a900bd32 100755
--- a/binary_search_tool/test/is_good_noinc_prune.py
+++ b/binary_search_tool/test/is_good_noinc_prune.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Check to see if the working set produces a good executable.
This test script is made for the noincremental-prune test. This makes sure
diff --git a/binary_search_tool/test/switch_tmp.py b/binary_search_tool/test/switch_tmp.py
index 165004ed..51b7110e 100755
--- a/binary_search_tool/test/switch_tmp.py
+++ b/binary_search_tool/test/switch_tmp.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Change portions of the object files to good.
This file is a test switch script. Used only for the test test_tmp_cleanup.
diff --git a/binary_search_tool/test/switch_to_bad.py b/binary_search_tool/test/switch_to_bad.py
index b8602421..a1b6bd59 100755
--- a/binary_search_tool/test/switch_to_bad.py
+++ b/binary_search_tool/test/switch_to_bad.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Switch part of the objects file in working set to (possible) bad ones."""
from __future__ import print_function
diff --git a/binary_search_tool/test/switch_to_bad_noinc_prune.py b/binary_search_tool/test/switch_to_bad_noinc_prune.py
index 87bf1584..db76acad 100755
--- a/binary_search_tool/test/switch_to_bad_noinc_prune.py
+++ b/binary_search_tool/test/switch_to_bad_noinc_prune.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Switch part of the objects file in working set to (possible) bad ones.
The "portion" is defined by the file (which is passed as the only argument to
diff --git a/binary_search_tool/test/switch_to_bad_set_file.py b/binary_search_tool/test/switch_to_bad_set_file.py
index f535fdfd..edf226d3 100755
--- a/binary_search_tool/test/switch_to_bad_set_file.py
+++ b/binary_search_tool/test/switch_to_bad_set_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Switch part of the objects file in working set to (possible) bad ones.
This script is meant to be specifically used with the set_file test. This uses
diff --git a/binary_search_tool/test/switch_to_good.py b/binary_search_tool/test/switch_to_good.py
index 68e9633f..59a118c1 100755
--- a/binary_search_tool/test/switch_to_good.py
+++ b/binary_search_tool/test/switch_to_good.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Change portions of the object files to good.
The "portion" is defined by the file (which is passed as the only argument to
diff --git a/binary_search_tool/test/switch_to_good_noinc_prune.py b/binary_search_tool/test/switch_to_good_noinc_prune.py
index c5e78e45..00488a74 100755
--- a/binary_search_tool/test/switch_to_good_noinc_prune.py
+++ b/binary_search_tool/test/switch_to_good_noinc_prune.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Change portions of the object files to good.
The "portion" is defined by the file (which is passed as the only argument to
diff --git a/binary_search_tool/test/switch_to_good_set_file.py b/binary_search_tool/test/switch_to_good_set_file.py
index 83777af0..b5e521f9 100755
--- a/binary_search_tool/test/switch_to_good_set_file.py
+++ b/binary_search_tool/test/switch_to_good_set_file.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Change portions of the object files to good.
The "portion" is defined by the file (which is passed as the only argument to
diff --git a/binary_search_tool/test/test_setup.py b/binary_search_tool/test/test_setup.py
index 3fb5a23c..0d6a410e 100755
--- a/binary_search_tool/test/test_setup.py
+++ b/binary_search_tool/test/test_setup.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Emulate running of test setup script, is_good.py should fail without this."""
from __future__ import print_function
diff --git a/binary_search_tool/test/test_setup_bad.py b/binary_search_tool/test/test_setup_bad.py
index 8d72763e..d715f57a 100755
--- a/binary_search_tool/test/test_setup_bad.py
+++ b/binary_search_tool/test/test_setup_bad.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python2
+#!/usr/bin/env python2
"""Emulate test setup that fails (i.e. failed flash to device)"""
from __future__ import print_function