| #!/usr/bin/python |
| # |
| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Unit tests for gsutil_util module.""" |
| |
| import subprocess |
| import time |
| import unittest |
| |
| import mox |
| |
| import gsutil_util |
| |
| |
| # pylint: disable=W0212 |
| class GSUtilUtilTest(mox.MoxTestBase): |
| |
| def setUp(self): |
| mox.MoxTestBase.setUp(self) |
| |
| 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 |
| |
| self._gs_run_setup = False |
| |
| def _CallRunGS(self, str_should_contain, attempts=1): |
| """Helper that wraps a RunGS for tests.""" |
| # Setup necessary stubs for gsutil invocation (just once). |
| if not self._gs_run_setup: |
| self._gs_run_setup = True |
| self.mox.StubOutWithMock(subprocess, 'Popen', use_mock_anything=True) |
| # Sleep only occurs if we expect to have multiple retry attempts. |
| if min(attempts, gsutil_util.GSUTIL_ATTEMPTS) > 1: |
| self.mox.StubOutWithMock(time, 'sleep') |
| time.sleep(mox.IgnoreArg()).MultipleTimes() |
| |
| for attempt in range(attempts): |
| if attempt == gsutil_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, |
| stderr=subprocess.PIPE).AndReturn(mock_process) |
| mock_process.communicate().AndReturn(('Does not matter', None)) |
| |
| def testDownloadFromGS(self): |
| """Tests that we can run download build from gs with one error.""" |
| # Make sure our retry works (but only if actually configured). |
| self._CallRunGS('from to', |
| attempts=min(2, gsutil_util.GSUTIL_ATTEMPTS)) |
| self.mox.ReplayAll() |
| gsutil_util.DownloadFromGS('from', 'to') |
| self.mox.VerifyAll() |
| |
| def testDownloadFromGSButGSDown(self): |
| """Tests that we fail correctly if we can't reach GS.""" |
| self._CallRunGS('from to', attempts=gsutil_util.GSUTIL_ATTEMPTS + 1) |
| self.mox.ReplayAll() |
| self.assertRaises( |
| gsutil_util.GSUtilError, |
| gsutil_util.DownloadFromGS, |
| 'from', 'to') |
| self.mox.VerifyAll() |
| |
| def testGetGSNamesWithWait(self): |
| """Test that we get the target artifact that is available.""" |
| archive_url = ('gs://chromeos-image-archive/x86-mario-release/' |
| 'R17-1413.0.0-a1-b1346') |
| name = 'chromeos_R17-1413.0.0-a1_x86-mario_full_dev.bin' |
| pattern = '*_full_*' |
| mock_data = 'mock data\nmock_data\nmock_data' |
| msg = 'UNIT TEST' |
| |
| self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun') |
| |
| # GSUtil cat gs://archive_url_prefix/UPLOADED. |
| gsutil_util.GSUtilRun(mox.StrContains(gsutil_util.UPLOADED_LIST), |
| mox.IgnoreArg()).AndReturn( |
| '%s\n%s' % (mock_data, name)) |
| |
| self.mox.ReplayAll() |
| # Timeout explicitly set to 0 to test that we always run at least once. |
| returned_names = gsutil_util.GetGSNamesWithWait( |
| pattern, archive_url, msg, delay=1, timeout=0) |
| self.assertEqual([name], returned_names) |
| self.mox.VerifyAll() |
| |
| def testGetGSNamesWithWaitWithDirectStat(self): |
| """We should directly stat an artifact whose name is fully spelled out.""" |
| archive_url = ('gs://chromeos-image-archive/x86-mario-release/' |
| 'R17-1413.0.0-a1-b1346') |
| name = 'chromeos_R17-1413.0.0-a1_x86-mario_full_dev.bin' |
| pattern = 'chromeos_R17-1413.0.0-a1_x86-mario_full_dev.bin' |
| mock_data = 'mock data\nmock_data\nmock_data' |
| msg = 'UNIT TEST' |
| |
| self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun') |
| |
| # GSUtil cat gs://archive_url_prefix/UPLOADED. |
| gsutil_util.GSUtilRun(mox.StrContains('gsutil stat %s/%s' % |
| (archive_url, pattern)), |
| mox.IgnoreArg()).AndReturn( |
| '%s\n%s' % (mock_data, name)) |
| |
| self.mox.ReplayAll() |
| # Timeout explicitly set to 0 to test that we always run at least once. |
| returned_names = gsutil_util.GetGSNamesWithWait( |
| pattern, archive_url, msg, delay=1, timeout=0) |
| self.assertEqual([name], returned_names) |
| self.mox.VerifyAll() |
| |
| def testGetGSNamesWithWaitWithRetry(self): |
| """Test that we can poll until all target artifacts are available.""" |
| archive_url = ('gs://chromeos-image-archive/x86-mario-release/' |
| 'R17-1413.0.0-a1-b1346') |
| name = 'chromeos_R17-1413.0.0-a1_x86-mario_full_dev.bin' |
| pattern = '*_full_*' |
| mock_data = 'mock data\nmock_data\nmock_data' |
| msg = 'UNIT TEST' |
| |
| self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun') |
| |
| # GSUtil cat gs://archive_url_prefix/UPLOADED. |
| gsutil_util.GSUtilRun(mox.StrContains(gsutil_util.UPLOADED_LIST), |
| mox.IgnoreArg()).AndReturn(mock_data) |
| |
| gsutil_util.GSUtilRun(mox.StrContains(gsutil_util.UPLOADED_LIST), |
| mox.IgnoreArg()).AndReturn( |
| '%s\n%s' % (mock_data, name)) |
| |
| self.mox.ReplayAll() |
| returned_names = gsutil_util.GetGSNamesWithWait( |
| pattern, archive_url, msg, delay=1, timeout=3) |
| self.assertEqual(name, returned_names[0]) |
| self.mox.VerifyAll() |
| |
| def testGetGSNamesWithWaitTimeout(self): |
| """Test that we wait for the target artifacts until timeout occurs.""" |
| archive_url = ('gs://chromeos-image-archive/x86-mario-release/' |
| 'R17-1413.0.0-a1-b1346') |
| pattern = '*_full_*' |
| mock_data = 'mock data\nmock_data\nmock_data' |
| msg = 'UNIT TEST' |
| |
| self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun') |
| |
| # GSUtil cat gs://archive_url_prefix/UPLOADED. |
| gsutil_util.GSUtilRun(mox.StrContains(gsutil_util.UPLOADED_LIST), |
| mox.IgnoreArg()).AndReturn(mock_data) |
| |
| self.mox.ReplayAll() |
| returned_name = gsutil_util.GetGSNamesWithWait( |
| pattern, archive_url, msg, delay=2, timeout=1) |
| self.assertEqual(returned_name, None) |
| self.mox.VerifyAll() |
| |
| def testGetLatestVersionFromGSDir(self): |
| """Test that we can get the most recent version from gsutil calls.""" |
| self.mox.StubOutWithMock(gsutil_util, 'GSUtilRun') |
| mock_data1 = '''gs://chromeos-releases/stable-channel/parrot/3701.96.0/ |
| gs://chromeos-releases/stable-channel/parrot/3701.98.0/ |
| gs://chromeos-releases/stable-channel/parrot/3912.100.0/ |
| gs://chromeos-releases/stable-channel/parrot/3912.101.0/ |
| gs://chromeos-releases/stable-channel/parrot/3912.79.0/ |
| gs://chromeos-releases/stable-channel/parrot/3912.79.1/''' |
| gsutil_util.GSUtilRun(mox.IgnoreArg(), |
| mox.IgnoreArg()).AndReturn(mock_data1) |
| mock_data2 = '''gs://chromeos-image-archive/parrot-release/R28-3912.101.0/a |
| gs://chromeos-image-archive/parrot-release/R28-3912.101.0/image.zip |
| gs://chromeos-image-archive/parrot-release/R28-3912.101.0/index.html |
| gs://chromeos-image-archive/parrot-release/R28-3912.101.0/metadata.json |
| gs://chromeos-image-archive/parrot-release/R28-3912.101.0/stateful.tgz''' |
| gsutil_util.GSUtilRun(mox.IgnoreArg(), |
| mox.IgnoreArg()).AndReturn(mock_data2) |
| self.mox.ReplayAll() |
| url = '' |
| self.assertEqual( |
| gsutil_util.GetLatestVersionFromGSDir(url, with_release=False), |
| '3912.101.0') |
| self.assertEqual( |
| gsutil_util.GetLatestVersionFromGSDir(url, with_release=True), |
| 'R28-3912.101.0') |
| self.mox.VerifyAll() |
| |
| if __name__ == '__main__': |
| unittest.main() |