Two fixes for AUTest to work on builders.

Fix timeout logic. It's possible for the builders to be going under so much
work that the timeout will pass before we enter the while loop. Fix this.

I've also gone ahead and check for error code 127 to avoid ever having an issue
where we can't find gsutil in the future. I spent a long time debugging this
before realizing the devserver couldn't find gsutil.

BUG=chromium:196387
TEST=Ran this code on a builder where it used to fail. Also ran unittests and
modified unittests to test new behavior.

Change-Id: Ibaeeb04c00c29783fc83547c4828972b1f38fce5
Reviewed-on: https://gerrit.chromium.org/gerrit/45505
Commit-Queue: Chris Sosa <sosa@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Tested-by: Chris Sosa <sosa@chromium.org>
diff --git a/gsutil_util.py b/gsutil_util.py
index a264cf7..32ab58e 100644
--- a/gsutil_util.py
+++ b/gsutil_util.py
@@ -50,11 +50,14 @@
     stdout, stderr = proc.communicate()
     if proc.returncode == 0:
       return stdout
-    elif 'matched no objects' in stderr or 'non-existent object' in stderr:
+    elif stderr and ('matched no objects' in stderr or
+                     'non-existent object' in stderr):
       # TODO(sosa): Note this is a heuristic that makes us not re-attempt
       # unnecessarily. However, if it fails, the worst that can happen is just
       # waiting longer than necessary.
       break
+    elif proc.returncode == 127:
+      raise GSUtilError('gsutil tool not found in your path.')
 
     time.sleep(sleep_timeout)
     sleep_timeout *= 2
@@ -112,9 +115,8 @@
     PatternNotSpecific: If caller sets single_item but multiple items match.
   """
   deadline = time.time() + timeout
-  while time.time() <= deadline:
+  while True:
     uploaded_list = []
-    to_delay = delay + random.uniform(.5 * delay, 1.5 * delay)
     try:
       cmd = 'gsutil cat %s/%s' % (archive_url, UPLOADED_LIST)
       msg = 'Failed to get a list of uploaded files.'
@@ -138,7 +140,10 @@
 
       return found_names
 
-    _Log('Retrying in %f seconds...%s', to_delay, err_str)
-    time.sleep(to_delay)
-
-  return None
+    # Don't delay past deadline.
+    to_delay = random.uniform(1.5 * delay, 2.5 * delay)
+    if to_delay < (deadline - time.time()):
+      _Log('Retrying in %f seconds...%s', to_delay, err_str)
+      time.sleep(to_delay)
+    else:
+      return None