Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / tools / telemetry / third_party / gsutilz / gslib / tests / test_update.py
blobb562950670edcee134c3264b5fad8a0de1d2180f
1 # -*- coding: utf-8 -*-
2 # Copyright 2013 Google Inc. All Rights Reserved.
4 # Permission is hereby granted, free of charge, to any person obtaining a
5 # copy of this software and associated documentation files (the
6 # "Software"), to deal in the Software without restriction, including
7 # without limitation the rights to use, copy, modify, merge, publish, dis-
8 # tribute, sublicense, and/or sell copies of the Software, and to permit
9 # persons to whom the Software is furnished to do so, subject to the fol-
10 # lowing conditions:
12 # The above copyright notice and this permission notice shall be included
13 # in all copies or substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 # IN THE SOFTWARE.
22 """Tests for the update command."""
24 from __future__ import absolute_import
26 import os.path
27 import shutil
28 import subprocess
29 import sys
30 import tarfile
32 import gslib
33 import gslib.tests.testcase as testcase
34 from gslib.tests.util import ObjectToURI as suri
35 from gslib.tests.util import unittest
36 from gslib.util import CERTIFICATE_VALIDATION_ENABLED
39 TESTS_DIR = os.path.abspath(os.path.dirname(__file__))
40 GSUTIL_DIR = os.path.join(TESTS_DIR, '..', '..')
43 class UpdateTest(testcase.GsUtilIntegrationTestCase):
44 """Update command test suite."""
46 @unittest.skipUnless(CERTIFICATE_VALIDATION_ENABLED,
47 'Test requires https certificate validation enabled.')
48 def test_update(self):
49 """Tests that the update command works or raises proper exceptions."""
50 if os.environ.get('CLOUDSDK_WRAPPER') == '1':
51 stderr = self.RunGsUtil(['update'], stdin='n',
52 return_stderr=True, expected_status=1)
53 self.assertIn('update command is disabled for Cloud SDK', stderr)
54 return
56 if gslib.IS_PACKAGE_INSTALL:
57 # The update command is not present when installed via package manager.
58 stderr = self.RunGsUtil(['update'], return_stderr=True, expected_status=1)
59 self.assertIn('Invalid command', stderr)
60 return
62 # Create two temp directories, one of which we will run 'gsutil update' in
63 # to pull the changes from the other.
64 tmpdir_src = self.CreateTempDir()
65 tmpdir_dst = self.CreateTempDir()
67 # Copy gsutil to both source and destination directories.
68 gsutil_src = os.path.join(tmpdir_src, 'gsutil')
69 gsutil_dst = os.path.join(tmpdir_dst, 'gsutil')
70 # Path when executing from tmpdir (Windows doesn't support in-place rename)
71 gsutil_relative_dst = os.path.join('gsutil', 'gsutil')
73 shutil.copytree(GSUTIL_DIR, gsutil_src)
74 # Copy specific files rather than all of GSUTIL_DIR so we don't pick up temp
75 # working files left in top-level directory by gsutil developers (like tags,
76 # .git*, etc.)
77 os.makedirs(gsutil_dst)
78 for comp in ('CHANGES.md', 'CHECKSUM', 'COPYING', 'gslib', 'gsutil',
79 'gsutil.py', 'MANIFEST.in', 'README.md', 'setup.py',
80 'third_party', 'VERSION'):
81 if os.path.isdir(os.path.join(GSUTIL_DIR, comp)):
82 func = shutil.copytree
83 else:
84 func = shutil.copyfile
85 func(os.path.join(GSUTIL_DIR, comp), os.path.join(gsutil_dst, comp))
87 # Create a fake version number in the source so we can verify it in the
88 # destination.
89 expected_version = '17.25'
90 src_version_file = os.path.join(gsutil_src, 'VERSION')
91 self.assertTrue(os.path.exists(src_version_file))
92 with open(src_version_file, 'w') as f:
93 f.write(expected_version)
95 # Create a tarball out of the source directory and copy it to a bucket.
96 src_tarball = os.path.join(tmpdir_src, 'gsutil.test.tar.gz')
98 normpath = os.path.normpath
99 try:
100 # We monkey patch os.path.normpath here because the tarfile module
101 # normalizes the ./gsutil path, but the update command expects the tar
102 # file to be prefixed with . This preserves the ./gsutil path.
103 os.path.normpath = lambda fname: fname
104 tar = tarfile.open(src_tarball, 'w:gz')
105 tar.add(gsutil_src, arcname='./gsutil')
106 tar.close()
107 finally:
108 os.path.normpath = normpath
110 prefix = [sys.executable] if sys.executable else []
112 # Run with an invalid gs:// URI.
113 p = subprocess.Popen(prefix + ['gsutil', 'update', 'gs://pub'],
114 cwd=gsutil_dst, stdout=subprocess.PIPE,
115 stderr=subprocess.PIPE)
116 (_, stderr) = p.communicate()
117 p.stdout.close()
118 p.stderr.close()
119 self.assertEqual(p.returncode, 1)
120 self.assertIn('update command only works with tar.gz', stderr)
122 # Run with non-existent gs:// URI.
123 p = subprocess.Popen(
124 prefix + ['gsutil', 'update', 'gs://pub/Jdjh38)(;.tar.gz'],
125 cwd=gsutil_dst, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
126 (_, stderr) = p.communicate()
127 p.stdout.close()
128 p.stderr.close()
129 self.assertEqual(p.returncode, 1)
130 self.assertIn('NotFoundException', stderr)
132 # Run with file:// URI wihout -f option.
133 p = subprocess.Popen(prefix + ['gsutil', 'update', suri(src_tarball)],
134 cwd=gsutil_dst, stdout=subprocess.PIPE,
135 stderr=subprocess.PIPE)
136 (_, stderr) = p.communicate()
137 p.stdout.close()
138 p.stderr.close()
139 self.assertEqual(p.returncode, 1)
140 self.assertIn('command does not support', stderr)
142 # Run with a file present that was not distributed with gsutil.
143 with open(os.path.join(gsutil_dst, 'userdata.txt'), 'w') as fp:
144 fp.write('important data\n')
145 p = subprocess.Popen(prefix + ['gsutil', 'update', '-f', suri(src_tarball)],
146 cwd=gsutil_dst, stdout=subprocess.PIPE,
147 stderr=subprocess.PIPE, stdin=subprocess.PIPE)
148 (_, stderr) = p.communicate()
149 p.stdout.close()
150 p.stderr.close()
151 # Clean up before next test, and before assertions so failure doesn't leave
152 # this file around.
153 os.unlink(os.path.join(gsutil_dst, 'userdata.txt'))
154 self.assertEqual(p.returncode, 1)
155 self.assertIn(
156 'The update command cannot run with user data in the gsutil directory',
157 stderr.replace(os.linesep, ' '))
159 # Now do the real update, which should succeed.
160 p = subprocess.Popen(prefix + [gsutil_relative_dst, 'update', '-f',
161 suri(src_tarball)],
162 cwd=tmpdir_dst, stdout=subprocess.PIPE,
163 stderr=subprocess.PIPE, stdin=subprocess.PIPE)
164 (_, stderr) = p.communicate(input='y\r\n')
165 p.stdout.close()
166 p.stderr.close()
167 self.assertEqual(p.returncode, 0, msg=(
168 'Non-zero return code (%d) from gsutil update. stderr = \n%s' %
169 (p.returncode, stderr)))
171 # Verify that version file was updated.
172 dst_version_file = os.path.join(tmpdir_dst, 'gsutil', 'VERSION')
173 with open(dst_version_file, 'r') as f:
174 self.assertEqual(f.read(), expected_version)