Retry all gsutil commands unconditionally for a max given attempt number.
This is necessary as gsutil can be somewhat flaky. This CL modifies
devserver_util to attempt to run gs commands up to 5x before reporting
an error.
BUG=chromium-os:27282
TEST=Unittests I added
Change-Id: I5a974b794a7b222e9671a550a24088ac80791839
Reviewed-on: https://gerrit.chromium.org/gerrit/17449
Tested-by: Chris Sosa <sosa@chromium.org>
Reviewed-by: Chris Masone <cmasone@chromium.org>
Commit-Ready: Chris Sosa <sosa@chromium.org>
diff --git a/devserver_util_test.py b/devserver_util_test.py
old mode 100644
new mode 100755
index dd09082..297aee1
--- a/devserver_util_test.py
+++ b/devserver_util_test.py
@@ -6,8 +6,10 @@
"""Unit tests for devserver_util module."""
+import mox
import os
import shutil
+import subprocess
import tempfile
import unittest
@@ -21,9 +23,10 @@
}
-class DevServerUtilTest(unittest.TestCase):
+class DevServerUtilTest(mox.MoxTestBase):
def setUp(self):
+ mox.MoxTestBase.setUp(self)
self._static_dir = tempfile.mkdtemp()
self._outside_sandbox_dir = tempfile.mkdtemp()
@@ -55,6 +58,11 @@
devserver_util.ROOT_UPDATE), 'w') as f:
f.write('ROOT_UPDATE')
+ self._good_mock_process = self.mox.CreateMock(subprocess.Popen)
+ self._good_mock_process.returncode = 0
+ self._bad_mock_process = self.mox.CreateMock(subprocess.Popen)
+ self._bad_mock_process.returncode = 1
+
def tearDown(self):
shutil.rmtree(self._static_dir)
shutil.rmtree(self._outside_sandbox_dir)
@@ -86,8 +94,64 @@
self.assertEqual([full_url, nton_url, mton_url],
[full_url_out, nton_url_out, mton_url_out])
+ def _CallRunGS(self, output, str_should_contain, attempts=1):
+ """Helper that wraps a RunGS for tests."""
+ for attempt in range(attempts):
+ if attempt == devserver_util.GSUTIL_ATTEMPTS:
+ # We can't mock more than we can attempt.
+ return
+
+ # Return 1's for all but last attempt.
+ if attempt != attempts - 1:
+ mock_process = self._bad_mock_process
+ else:
+ mock_process = self._good_mock_process
+
+ subprocess.Popen(mox.StrContains(str_should_contain), shell=True,
+ stdout=subprocess.PIPE).AndReturn(mock_process)
+ mock_process.communicate().AndReturn((output, None))
+
def testDownloadBuildFromGS(self):
- self.fail('Not implemented.')
+ """Tests that we can run download build from gs with one error."""
+ build = 'R17-1413.0.0-a1-b1346'
+ archive_url_prefix = ('gs://chromeos-image-archive/x86-mario-release/' +
+ build)
+ mock_data = 'mock data\nmock_data\nmock_data'
+ payloads = ['p1', 'p2', 'p3']
+ self.mox.StubOutWithMock(subprocess, 'Popen', use_mock_anything=True)
+ self.mox.StubOutWithMock(devserver_util, 'ParsePayloadList')
+
+ # Make sure we our retry works.
+ self._CallRunGS(mock_data, archive_url_prefix, attempts=2)
+ devserver_util.ParsePayloadList(mock_data.splitlines()).AndReturn(
+ payloads)
+
+ for payload in payloads + [devserver_util.STATEFUL_UPDATE,
+ devserver_util.AUTOTEST_PACKAGE]:
+ self._CallRunGS(mock_data, payload,)
+
+ self.mox.ReplayAll()
+ devserver_util.DownloadBuildFromGS(self._static_dir, archive_url_prefix,
+ build)
+ self.mox.VerifyAll()
+
+ def testDownloadBuildFromGSButGSDown(self):
+ """Tests that we fail correctly if we can't reach GS."""
+ build = 'R17-1413.0.0-a1-b1346'
+ archive_url_prefix = ('gs://chromeos-image-archive/x86-mario-release/' +
+ build)
+ mock_data = 'mock data\nmock_data\nmock_data'
+ self.mox.StubOutWithMock(subprocess, 'Popen', use_mock_anything=True)
+
+ self._CallRunGS(mock_data, archive_url_prefix,
+ attempts=devserver_util.GSUTIL_ATTEMPTS + 1)
+
+ self.mox.ReplayAll()
+ self.assertRaises(
+ devserver_util.DevServerUtilError,
+ devserver_util.DownloadBuildFromGS,
+ self._static_dir, archive_url_prefix, build)
+ self.mox.VerifyAll()
def testInstallBuild(self):
self.fail('Not implemented.')
@@ -235,14 +299,14 @@
def testGetControlFile(self):
control_file_dir = os.path.join(
- self._static_dir, 'test-board-1', 'R17-1413.0.0-a1-b1346', 'server',
- 'site_tests', 'network_VPN')
+ self._static_dir, 'test-board-1', 'R17-1413.0.0-a1-b1346', 'autotest',
+ 'server', 'site_tests', 'network_VPN')
os.makedirs(control_file_dir)
with open(os.path.join(control_file_dir, 'control'), 'w') as f:
f.write('hello!')
control_content = devserver_util.GetControlFile(
- self._static_dir, 'test-board-1', 'R17-1413.0.0-a1-b1346',
+ self._static_dir, 'test-board-1/R17-1413.0.0-a1-b1346',
os.path.join('server', 'site_tests', 'network_VPN', 'control'))
self.assertEqual(control_content, 'hello!')