| OLD | NEW |
| (Empty) |
| 1 # -*- coding: utf-8 -*- | |
| 2 # Copyright 2010 Google Inc. All Rights Reserved. | |
| 3 # | |
| 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: | |
| 11 # | |
| 12 # The above copyright notice and this permission notice shall be included | |
| 13 # in all copies or substantial portions of the Software. | |
| 14 # | |
| 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 gsutil naming logic. | |
| 23 | |
| 24 The test code in this file runs against an in-memory storage service mock, | |
| 25 so runs very quickly. This is valuable for testing changes that impact the | |
| 26 naming rules, since those rules are complex and it's useful to be able to | |
| 27 make small incremental changes and rerun the tests frequently. Additional | |
| 28 end-to-end tests (which send traffic to the production Google Cloud Storage | |
| 29 service) are available via the gsutil test command. | |
| 30 """ | |
| 31 | |
| 32 from __future__ import absolute_import | |
| 33 | |
| 34 import gzip | |
| 35 import os | |
| 36 import StringIO | |
| 37 | |
| 38 from gslib import copy_helper | |
| 39 from gslib.cloud_api import NotFoundException | |
| 40 from gslib.cloud_api import ServiceException | |
| 41 from gslib.exception import CommandException | |
| 42 from gslib.exception import HashMismatchException | |
| 43 from gslib.storage_url import StorageUrlFromString | |
| 44 import gslib.tests.testcase as testcase | |
| 45 from gslib.tests.util import ObjectToURI as suri | |
| 46 from gslib.tests.util import SetBotoConfigForTest | |
| 47 from gslib.util import UTF8 | |
| 48 | |
| 49 | |
| 50 def _Overwrite(fp): | |
| 51 """Overwrite first byte in an open file and flush contents.""" | |
| 52 fp.seek(0) | |
| 53 fp.write('x') | |
| 54 fp.flush() | |
| 55 | |
| 56 | |
| 57 def _Append(fp): | |
| 58 """Append a byte at end of an open file and flush contents.""" | |
| 59 fp.seek(0, 2) | |
| 60 fp.write('x') | |
| 61 fp.flush() | |
| 62 | |
| 63 | |
| 64 # TODO: Re-enable PerformsFileToObjectUpload decorator on tests in this file | |
| 65 # once we refactor to a thread-safe mock storage service implementation. | |
| 66 class GsutilNamingTests(testcase.GsUtilUnitTestCase): | |
| 67 """Unit tests for gsutil naming logic.""" | |
| 68 | |
| 69 def testGetPathBeforeFinalDir(self): | |
| 70 """Tests GetPathBeforeFinalDir() (unit test).""" | |
| 71 self.assertEqual( | |
| 72 'gs://', copy_helper.GetPathBeforeFinalDir(StorageUrlFromString( | |
| 73 'gs://bucket/'))) | |
| 74 self.assertEqual( | |
| 75 'gs://bucket', copy_helper.GetPathBeforeFinalDir(StorageUrlFromString( | |
| 76 'gs://bucket/dir/'))) | |
| 77 self.assertEqual( | |
| 78 'gs://bucket', copy_helper.GetPathBeforeFinalDir(StorageUrlFromString( | |
| 79 'gs://bucket/dir'))) | |
| 80 self.assertEqual( | |
| 81 'gs://bucket/dir', copy_helper.GetPathBeforeFinalDir( | |
| 82 StorageUrlFromString('gs://bucket/dir/obj'))) | |
| 83 src_dir = self.CreateTempDir() | |
| 84 subdir = os.path.join(src_dir, 'subdir') | |
| 85 os.mkdir(subdir) | |
| 86 self.assertEqual(suri(src_dir), | |
| 87 copy_helper.GetPathBeforeFinalDir( | |
| 88 StorageUrlFromString(suri(subdir)))) | |
| 89 | |
| 90 # @PerformsFileToObjectUpload | |
| 91 def testCopyingTopLevelFileToBucket(self): | |
| 92 """Tests copying one top-level file to a bucket.""" | |
| 93 src_file = self.CreateTempFile(file_name='f0') | |
| 94 dst_bucket_uri = self.CreateBucket() | |
| 95 self.RunCommand('cp', [src_file, suri(dst_bucket_uri)]) | |
| 96 actual = list(self._test_wildcard_iterator( | |
| 97 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 98 self.assertEqual(1, len(actual)) | |
| 99 self.assertEqual('f0', actual[0].root_object.name) | |
| 100 | |
| 101 # @PerformsFileToObjectUpload | |
| 102 def testCopyingMultipleFilesToBucket(self): | |
| 103 """Tests copying multiple files to a bucket.""" | |
| 104 src_file0 = self.CreateTempFile(file_name='f0') | |
| 105 src_file1 = self.CreateTempFile(file_name='f1') | |
| 106 dst_bucket_uri = self.CreateBucket() | |
| 107 self.RunCommand('cp', [src_file0, src_file1, suri(dst_bucket_uri)]) | |
| 108 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 109 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 110 expected = set([ | |
| 111 suri(dst_bucket_uri, 'f0'), | |
| 112 suri(dst_bucket_uri, 'f1'), | |
| 113 ]) | |
| 114 self.assertEqual(expected, actual) | |
| 115 | |
| 116 # @PerformsFileToObjectUpload | |
| 117 def testCopyingNestedFileToBucketSubdir(self): | |
| 118 """Tests copying a nested file to a bucket subdir. | |
| 119 | |
| 120 Tests that we correctly translate local FS-specific delimiters ('\' on | |
| 121 Windows) to bucket delimiter (/). | |
| 122 """ | |
| 123 tmpdir = self.CreateTempDir() | |
| 124 subdir = os.path.join(tmpdir, 'subdir') | |
| 125 os.mkdir(subdir) | |
| 126 src_file = self.CreateTempFile(tmpdir=tmpdir, file_name='obj', contents='') | |
| 127 dst_bucket_uri = self.CreateBucket() | |
| 128 # Make an object under subdir so next copy will treat subdir as a subdir. | |
| 129 self.RunCommand('cp', [src_file, suri(dst_bucket_uri, 'subdir/a')]) | |
| 130 self.RunCommand('cp', [src_file, suri(dst_bucket_uri, 'subdir')]) | |
| 131 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 132 suri(dst_bucket_uri, '**')).IterObjects()) | |
| 133 expected = set([ | |
| 134 suri(dst_bucket_uri, 'subdir', 'a'), | |
| 135 suri(dst_bucket_uri, 'subdir', 'obj'), | |
| 136 ]) | |
| 137 self.assertEqual(expected, actual) | |
| 138 | |
| 139 # @PerformsFileToObjectUpload | |
| 140 def testCopyingAbsolutePathDirToBucket(self): | |
| 141 """Tests recursively copying absolute path directory to a bucket.""" | |
| 142 dst_bucket_uri = self.CreateBucket() | |
| 143 src_dir_root = self.CreateTempDir(test_files=[ | |
| 144 'f0', 'f1', 'f2.txt', ('dir0', 'dir1', 'nested')]) | |
| 145 self.RunCommand('cp', ['-R', src_dir_root, suri(dst_bucket_uri)]) | |
| 146 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 147 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 148 src_tmpdir = os.path.split(src_dir_root)[1] | |
| 149 expected = set([ | |
| 150 suri(dst_bucket_uri, src_tmpdir, 'f0'), | |
| 151 suri(dst_bucket_uri, src_tmpdir, 'f1'), | |
| 152 suri(dst_bucket_uri, src_tmpdir, 'f2.txt'), | |
| 153 suri(dst_bucket_uri, src_tmpdir, 'dir0', 'dir1', 'nested')]) | |
| 154 self.assertEqual(expected, actual) | |
| 155 | |
| 156 # @PerformsFileToObjectUpload | |
| 157 def testCopyingRelativePathDirToBucket(self): | |
| 158 """Tests recursively copying relative directory to a bucket.""" | |
| 159 dst_bucket_uri = self.CreateBucket() | |
| 160 src_dir = self.CreateTempDir(test_files=[('dir0', 'f1')]) | |
| 161 self.RunCommand('cp', ['-R', 'dir0', suri(dst_bucket_uri)], cwd=src_dir) | |
| 162 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 163 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 164 expected = set([suri(dst_bucket_uri, 'dir0', 'f1')]) | |
| 165 self.assertEqual(expected, actual) | |
| 166 | |
| 167 # @PerformsFileToObjectUpload | |
| 168 def testCopyingRelPathSubDirToBucketSubdirWithDollarFolderObj(self): | |
| 169 """Tests recursively copying relative sub-directory to bucket subdir. | |
| 170 | |
| 171 Subdir is signified by a $folder$ object. | |
| 172 """ | |
| 173 # Create a $folder$ object to simulate a folder created by GCS manager (or | |
| 174 # various other tools), which gsutil understands to mean there is a folder | |
| 175 # into which the object is being copied. | |
| 176 dst_bucket_uri = self.CreateBucket() | |
| 177 self.CreateObject(bucket_uri=dst_bucket_uri, object_name='abc_$folder$', | |
| 178 contents='') | |
| 179 src_dir = self.CreateTempDir(test_files=[('dir0', 'dir1', 'f1')]) | |
| 180 self.RunCommand('cp', ['-R', os.path.join('dir0', 'dir1'), | |
| 181 suri(dst_bucket_uri, 'abc')], cwd=src_dir) | |
| 182 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 183 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 184 expected = set([suri(dst_bucket_uri, 'abc_$folder$'), | |
| 185 suri(dst_bucket_uri, 'abc', 'dir1', 'f1')]) | |
| 186 self.assertEqual(expected, actual) | |
| 187 | |
| 188 # @PerformsFileToObjectUpload | |
| 189 def testCopyingRelativePathSubDirToBucketSubdirSignifiedBySlash(self): | |
| 190 """Tests recursively copying relative sub-directory to bucket subdir. | |
| 191 | |
| 192 Subdir is signified by a / object. | |
| 193 """ | |
| 194 dst_bucket_uri = self.CreateBucket() | |
| 195 src_dir = self.CreateTempDir(test_files=[('dir0', 'dir1', 'f1')]) | |
| 196 self.RunCommand('cp', ['-R', os.path.join('dir0', 'dir1'), | |
| 197 suri(dst_bucket_uri, 'abc') + '/'], cwd=src_dir) | |
| 198 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 199 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 200 expected = set([suri(dst_bucket_uri, 'abc', 'dir1', 'f1')]) | |
| 201 self.assertEqual(expected, actual) | |
| 202 | |
| 203 # @PerformsFileToObjectUpload | |
| 204 def testCopyingRelativePathSubDirToBucket(self): | |
| 205 """Tests recursively copying relative sub-directory to a bucket.""" | |
| 206 dst_bucket_uri = self.CreateBucket() | |
| 207 src_dir = self.CreateTempDir(test_files=[('dir0', 'dir1', 'f1')]) | |
| 208 self.RunCommand('cp', ['-R', os.path.join('dir0', 'dir1'), | |
| 209 suri(dst_bucket_uri)], cwd=src_dir) | |
| 210 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 211 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 212 expected = set([suri(dst_bucket_uri, 'dir1', 'f1')]) | |
| 213 self.assertEqual(expected, actual) | |
| 214 | |
| 215 # @PerformsFileToObjectUpload | |
| 216 def testCopyingDotSlashToBucket(self): | |
| 217 """Tests copying ./ to a bucket produces expected naming.""" | |
| 218 # When running a command like gsutil cp -r . gs://dest we expect the dest | |
| 219 # obj names to be of the form gs://dest/abc, not gs://dest/./abc. | |
| 220 dst_bucket_uri = self.CreateBucket() | |
| 221 src_dir = self.CreateTempDir(test_files=['foo']) | |
| 222 for rel_src_dir in ['.', '.%s' % os.sep]: | |
| 223 self.RunCommand('cp', ['-R', rel_src_dir, suri(dst_bucket_uri)], | |
| 224 cwd=src_dir) | |
| 225 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 226 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 227 expected = set([suri(dst_bucket_uri, 'foo')]) | |
| 228 self.assertEqual(expected, actual) | |
| 229 | |
| 230 # @PerformsFileToObjectUpload | |
| 231 def testCopyingDirContainingOneFileToBucket(self): | |
| 232 """Tests copying a directory containing 1 file to a bucket. | |
| 233 | |
| 234 We test this case to ensure that correct bucket handling isn't dependent | |
| 235 on the copy being treated as a multi-source copy. | |
| 236 """ | |
| 237 dst_bucket_uri = self.CreateBucket() | |
| 238 src_dir = self.CreateTempDir(test_files=[('dir0', 'dir1', 'foo')]) | |
| 239 self.RunCommand('cp', ['-R', os.path.join(src_dir, 'dir0', 'dir1'), | |
| 240 suri(dst_bucket_uri)]) | |
| 241 actual = list((str(u) for u in self._test_wildcard_iterator( | |
| 242 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True))) | |
| 243 self.assertEqual(1, len(actual)) | |
| 244 self.assertEqual(suri(dst_bucket_uri, 'dir1', 'foo'), actual[0]) | |
| 245 | |
| 246 def testCopyingBucketToDir(self): | |
| 247 """Tests copying from a bucket to a directory.""" | |
| 248 src_bucket_uri = self.CreateBucket(test_objects=['foo', 'dir/foo2']) | |
| 249 dst_dir = self.CreateTempDir() | |
| 250 # Mock objects don't support hash digestion. | |
| 251 with SetBotoConfigForTest([('GSUtil', 'check_hashes', 'never')]): | |
| 252 self.RunCommand('cp', ['-R', suri(src_bucket_uri), dst_dir]) | |
| 253 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 254 '%s%s**' % (dst_dir, os.sep)).IterAll(expand_top_level_buckets=True)) | |
| 255 expected = set([suri(dst_dir, src_bucket_uri.bucket_name, 'foo'), | |
| 256 suri(dst_dir, src_bucket_uri.bucket_name, 'dir', 'foo2')]) | |
| 257 self.assertEqual(expected, actual) | |
| 258 | |
| 259 def testCopyingBucketToBucket(self): | |
| 260 """Tests copying from a bucket-only URI to a bucket.""" | |
| 261 src_bucket_uri = self.CreateBucket(test_objects=['foo', 'dir/foo2']) | |
| 262 dst_bucket_uri = self.CreateBucket() | |
| 263 self.RunCommand('cp', ['-R', suri(src_bucket_uri), suri(dst_bucket_uri)]) | |
| 264 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 265 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 266 expected = set([ | |
| 267 suri(dst_bucket_uri, src_bucket_uri.bucket_name, 'foo'), | |
| 268 suri(dst_bucket_uri, src_bucket_uri.bucket_name, 'dir', 'foo2')]) | |
| 269 self.assertEqual(expected, actual) | |
| 270 | |
| 271 def testCopyingDirectoryToDirectory(self): | |
| 272 """Tests copying from a directory to a directory.""" | |
| 273 src_dir = self.CreateTempDir(test_files=['foo', ('dir', 'foo2')]) | |
| 274 dst_dir = self.CreateTempDir() | |
| 275 self.RunCommand('cp', ['-R', src_dir, dst_dir]) | |
| 276 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 277 '%s%s**' % (dst_dir, os.sep)).IterAll(expand_top_level_buckets=True)) | |
| 278 src_dir_base = os.path.split(src_dir)[1] | |
| 279 expected = set([suri(dst_dir, src_dir_base, 'foo'), | |
| 280 suri(dst_dir, src_dir_base, 'dir', 'foo2')]) | |
| 281 self.assertEqual(expected, actual) | |
| 282 | |
| 283 def testCopyingFilesAndDirNonRecursive(self): | |
| 284 """Tests copying containing files and a directory without -R.""" | |
| 285 src_dir = self.CreateTempDir(test_files=['foo', 'bar', ('d1', 'f2'), | |
| 286 ('d2', 'f3'), ('d3', 'd4', 'f4')]) | |
| 287 dst_dir = self.CreateTempDir() | |
| 288 self.RunCommand('cp', ['%s%s*' % (src_dir, os.sep), dst_dir]) | |
| 289 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 290 '%s%s**' % (dst_dir, os.sep)).IterAll(expand_top_level_buckets=True)) | |
| 291 expected = set([suri(dst_dir, 'foo'), suri(dst_dir, 'bar')]) | |
| 292 self.assertEqual(expected, actual) | |
| 293 | |
| 294 def testCopyingFileToDir(self): | |
| 295 """Tests copying one file to a directory.""" | |
| 296 src_file = self.CreateTempFile(file_name='foo') | |
| 297 dst_dir = self.CreateTempDir() | |
| 298 self.RunCommand('cp', [src_file, dst_dir]) | |
| 299 actual = list(self._test_wildcard_iterator( | |
| 300 '%s%s*' % (dst_dir, os.sep)).IterAll(expand_top_level_buckets=True)) | |
| 301 self.assertEqual(1, len(actual)) | |
| 302 self.assertEqual(suri(dst_dir, 'foo'), str(actual[0])) | |
| 303 | |
| 304 # @PerformsFileToObjectUpload | |
| 305 def testCopyingFileToObjectWithConsecutiveSlashes(self): | |
| 306 """Tests copying a file to an object containing consecutive slashes.""" | |
| 307 src_file = self.CreateTempFile(file_name='f0') | |
| 308 dst_bucket_uri = self.CreateBucket() | |
| 309 self.RunCommand('cp', [src_file, suri(dst_bucket_uri) + '//obj']) | |
| 310 actual = list(self._test_wildcard_iterator( | |
| 311 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 312 self.assertEqual(1, len(actual)) | |
| 313 self.assertEqual('/obj', actual[0].root_object.name) | |
| 314 | |
| 315 def testCopyingCompressedFileToBucket(self): | |
| 316 """Tests copying one file with compression to a bucket.""" | |
| 317 src_file = self.CreateTempFile(contents='plaintext', file_name='f2.txt') | |
| 318 dst_bucket_uri = self.CreateBucket() | |
| 319 self.RunCommand('cp', ['-z', 'txt', src_file, suri(dst_bucket_uri)],) | |
| 320 actual = list(self._test_wildcard_iterator( | |
| 321 suri(dst_bucket_uri, '*')).IterAll(expand_top_level_buckets=True)) | |
| 322 self.assertEqual(1, len(actual)) | |
| 323 actual_obj = actual[0].root_object | |
| 324 self.assertEqual('f2.txt', actual_obj.name) | |
| 325 self.assertEqual('gzip', actual_obj.contentEncoding) | |
| 326 | |
| 327 stdout = self.RunCommand('cat', [suri(dst_bucket_uri, 'f2.txt')], | |
| 328 return_stdout=True) | |
| 329 | |
| 330 f = gzip.GzipFile(fileobj=StringIO.StringIO(stdout), mode='rb') | |
| 331 try: | |
| 332 self.assertEqual(f.read(), 'plaintext') | |
| 333 finally: | |
| 334 f.close() | |
| 335 | |
| 336 def testCopyingObjectToObject(self): | |
| 337 """Tests copying an object to an object.""" | |
| 338 src_bucket_uri = self.CreateBucket(test_objects=['obj']) | |
| 339 dst_bucket_uri = self.CreateBucket() | |
| 340 self.RunCommand('cp', [suri(src_bucket_uri, 'obj'), suri(dst_bucket_uri)]) | |
| 341 actual = list(self._test_wildcard_iterator( | |
| 342 suri(dst_bucket_uri, '*')).IterAll(expand_top_level_buckets=True)) | |
| 343 self.assertEqual(1, len(actual)) | |
| 344 self.assertEqual('obj', actual[0].root_object.name) | |
| 345 | |
| 346 def testCopyingObjectToObjectUsingDestWildcard(self): | |
| 347 """Tests copying an object to an object using a dest wildcard.""" | |
| 348 src_bucket_uri = self.CreateBucket(test_objects=['obj']) | |
| 349 dst_bucket_uri = self.CreateBucket(test_objects=['dstobj']) | |
| 350 self.RunCommand('cp', [suri(src_bucket_uri, 'obj'), | |
| 351 '%s*' % dst_bucket_uri.uri]) | |
| 352 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 353 suri(dst_bucket_uri, '*')).IterAll(expand_top_level_buckets=True)) | |
| 354 expected = set([suri(dst_bucket_uri, 'dstobj')]) | |
| 355 self.assertEqual(expected, actual) | |
| 356 | |
| 357 def testCopyingObjsAndFilesToDir(self): | |
| 358 """Tests copying objects and files to a directory.""" | |
| 359 src_bucket_uri = self.CreateBucket(test_objects=['f1']) | |
| 360 src_dir = self.CreateTempDir(test_files=['f2']) | |
| 361 dst_dir = self.CreateTempDir() | |
| 362 # Mock objects don't support hash digestion. | |
| 363 with SetBotoConfigForTest([('GSUtil', 'check_hashes', 'never')]): | |
| 364 self.RunCommand('cp', ['-R', suri(src_bucket_uri, '**'), | |
| 365 os.path.join(src_dir, '**'), dst_dir]) | |
| 366 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 367 os.path.join(dst_dir, '**')).IterAll(expand_top_level_buckets=True)) | |
| 368 expected = set([suri(dst_dir, 'f1'), suri(dst_dir, 'f2')]) | |
| 369 self.assertEqual(expected, actual) | |
| 370 | |
| 371 def testCopyingObjToDot(self): | |
| 372 """Tests that copying an object to . or ./ downloads to correct name.""" | |
| 373 src_bucket_uri = self.CreateBucket(test_objects=['f1']) | |
| 374 dst_dir = self.CreateTempDir() | |
| 375 for final_char in ('/', ''): | |
| 376 # Mock objects don't support hash digestion. | |
| 377 with SetBotoConfigForTest([('GSUtil', 'check_hashes', 'never')]): | |
| 378 self.RunCommand('cp', [suri(src_bucket_uri, 'f1'), '.%s' % final_char], | |
| 379 cwd=dst_dir) | |
| 380 actual = set() | |
| 381 for dirname, dirnames, filenames in os.walk(dst_dir): | |
| 382 for subdirname in dirnames: | |
| 383 actual.add(os.path.join(dirname, subdirname)) | |
| 384 for filename in filenames: | |
| 385 actual.add(os.path.join(dirname, filename)) | |
| 386 expected = set([os.path.join(dst_dir, 'f1')]) | |
| 387 self.assertEqual(expected, actual) | |
| 388 | |
| 389 # @PerformsFileToObjectUpload | |
| 390 def testCopyingObjsAndFilesToBucket(self): | |
| 391 """Tests copying objects and files to a bucket.""" | |
| 392 src_bucket_uri = self.CreateBucket(test_objects=['f1']) | |
| 393 src_dir = self.CreateTempDir(test_files=['f2']) | |
| 394 dst_bucket_uri = self.CreateBucket() | |
| 395 self.RunCommand('cp', ['-R', suri(src_bucket_uri, '**'), | |
| 396 '%s%s**' % (src_dir, os.sep), suri(dst_bucket_uri)]) | |
| 397 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 398 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 399 expected = set([suri(dst_bucket_uri, 'f1'), suri(dst_bucket_uri, 'f2')]) | |
| 400 self.assertEqual(expected, actual) | |
| 401 | |
| 402 # @PerformsFileToObjectUpload | |
| 403 def testCopyingSubdirRecursiveToNonexistentSubdir(self): | |
| 404 """Tests copying a directory with a single file recursively to a bucket. | |
| 405 | |
| 406 The file should end up in a new bucket subdirectory with the file's | |
| 407 directory structure starting below the recursive copy point, as in Unix cp. | |
| 408 | |
| 409 Example: | |
| 410 filepath: dir1/dir2/foo | |
| 411 cp -r dir1 dir3 | |
| 412 Results in dir3/dir2/foo being created. | |
| 413 """ | |
| 414 src_dir = self.CreateTempDir() | |
| 415 self.CreateTempFile(tmpdir=src_dir + '/dir1/dir2', file_name='foo') | |
| 416 dst_bucket_uri = self.CreateBucket() | |
| 417 self.RunCommand('cp', ['-R', src_dir + '/dir1', | |
| 418 suri(dst_bucket_uri, 'dir3')]) | |
| 419 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 420 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 421 expected = set([suri(dst_bucket_uri, 'dir3/dir2/foo')]) | |
| 422 self.assertEqual(expected, actual) | |
| 423 | |
| 424 def testAttemptDirCopyWithoutRecursion(self): | |
| 425 """Tests copying a directory without -R.""" | |
| 426 src_dir = self.CreateTempDir(test_files=1) | |
| 427 dst_dir = self.CreateTempDir() | |
| 428 try: | |
| 429 self.RunCommand('cp', [src_dir, dst_dir]) | |
| 430 self.fail('Did not get expected CommandException') | |
| 431 except CommandException, e: | |
| 432 self.assertIn('No URLs matched', e.reason) | |
| 433 | |
| 434 def testNonRecursiveFileAndSameNameSubdir(self): | |
| 435 """Tests copying a file and subdirectory of the same name without -R.""" | |
| 436 src_bucket_uri = self.CreateBucket(test_objects=['f1', 'f1/f2']) | |
| 437 dst_dir = self.CreateTempDir() | |
| 438 # Mock objects don't support hash digestion. | |
| 439 with SetBotoConfigForTest([('GSUtil', 'check_hashes', 'never')]): | |
| 440 self.RunCommand('cp', [suri(src_bucket_uri, 'f1'), dst_dir]) | |
| 441 actual = list(self._test_wildcard_iterator( | |
| 442 '%s%s*' % (dst_dir, os.sep)).IterAll(expand_top_level_buckets=True)) | |
| 443 self.assertEqual(1, len(actual)) | |
| 444 self.assertEqual(suri(dst_dir, 'f1'), str(actual[0])) | |
| 445 # TODO: Assert that we omit the prefix here when unit_testcase supports | |
| 446 # returning stderr. | |
| 447 | |
| 448 def testAttemptCopyingProviderOnlySrc(self): | |
| 449 """Attempts to copy a src specified as a provider-only URI.""" | |
| 450 src_bucket_uri = self.CreateBucket() | |
| 451 try: | |
| 452 self.RunCommand('cp', ['gs://', suri(src_bucket_uri)]) | |
| 453 self.fail('Did not get expected CommandException') | |
| 454 except CommandException, e: | |
| 455 self.assertIn('provider-only', e.reason) | |
| 456 | |
| 457 def testAttemptCopyingOverlappingSrcDstFile(self): | |
| 458 """Attempts to an object atop itself.""" | |
| 459 src_file = self.CreateTempFile() | |
| 460 try: | |
| 461 self.RunCommand('cp', [src_file, src_file]) | |
| 462 self.fail('Did not get expected CommandException') | |
| 463 except CommandException, e: | |
| 464 self.assertIn('are the same file - abort', e.reason) | |
| 465 | |
| 466 def testAttemptCopyingToMultiMatchWildcard(self): | |
| 467 """Attempts to copy where dst wildcard matches >1 obj.""" | |
| 468 src_bucket_uri = self.CreateBucket(test_objects=2) | |
| 469 try: | |
| 470 self.RunCommand('cp', [suri(src_bucket_uri, 'obj0'), | |
| 471 suri(src_bucket_uri, '*')]) | |
| 472 self.fail('Did not get expected CommandException') | |
| 473 except CommandException, e: | |
| 474 self.assertNotEqual(e.reason.find('must match exactly 1 URL'), -1) | |
| 475 | |
| 476 def testAttemptCopyingMultiObjsToFile(self): | |
| 477 """Attempts to copy multiple objects to a file.""" | |
| 478 src_bucket_uri = self.CreateBucket(test_objects=2) | |
| 479 dst_file = self.CreateTempFile() | |
| 480 try: | |
| 481 self.RunCommand('cp', ['-R', suri(src_bucket_uri, '*'), dst_file]) | |
| 482 self.fail('Did not get expected CommandException') | |
| 483 except CommandException, e: | |
| 484 self.assertIn('must name a directory, bucket, or', e.reason) | |
| 485 | |
| 486 def testAttemptCopyingWithFileDirConflict(self): | |
| 487 """Attempts to copy objects that cause a file/directory conflict.""" | |
| 488 # Create objects with name conflicts (a/b and a). Use 'dst' bucket because | |
| 489 # it gets cleared after each test. | |
| 490 bucket_uri = self.CreateBucket() | |
| 491 self.CreateObject(bucket_uri=bucket_uri, object_name='a') | |
| 492 self.CreateObject(bucket_uri=bucket_uri, object_name='b/a') | |
| 493 dst_dir = self.CreateTempDir() | |
| 494 try: | |
| 495 self.RunCommand('cp', ['-R', suri(bucket_uri), dst_dir]) | |
| 496 self.fail('Did not get expected CommandException') | |
| 497 except CommandException, e: | |
| 498 self.assertNotEqual('exists where a directory needs to be created', | |
| 499 e.reason) | |
| 500 | |
| 501 def testAttemptCopyingWithDirFileConflict(self): | |
| 502 """Attempts to copy an object that causes a directory/file conflict.""" | |
| 503 # Create an object that conflicts with dest subdir. | |
| 504 tmpdir = self.CreateTempDir() | |
| 505 os.mkdir(os.path.join(tmpdir, 'abc')) | |
| 506 src_uri = self.CreateObject(object_name='abc', contents='bar') | |
| 507 try: | |
| 508 self.RunCommand('cp', [suri(src_uri), tmpdir + '/']) | |
| 509 self.fail('Did not get expected CommandException') | |
| 510 except CommandException, e: | |
| 511 self.assertNotEqual('where the file needs to be created', e.reason) | |
| 512 | |
| 513 def testWildcardMoveWithinBucket(self): | |
| 514 """Attempts to move using src wildcard that overlaps dest object. | |
| 515 | |
| 516 We want to ensure that this doesn't stomp the result data. | |
| 517 """ | |
| 518 dst_bucket_uri = self.CreateBucket(test_objects=['old']) | |
| 519 self.RunCommand('mv', [suri(dst_bucket_uri, 'old*'), | |
| 520 suri(dst_bucket_uri, 'new')]) | |
| 521 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 522 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 523 expected = set([suri(dst_bucket_uri, 'new')]) | |
| 524 self.assertEqual(expected, actual) | |
| 525 | |
| 526 def testLsNonExistentObjectWithPrefixName(self): | |
| 527 """Test ls of non-existent obj that matches prefix of existing objs.""" | |
| 528 # Use an object name that matches a prefix of other names at that level, to | |
| 529 # ensure the ls subdir handling logic doesn't pick up anything extra. | |
| 530 src_bucket_uri = self.CreateBucket(test_objects=['obj_with_suffix']) | |
| 531 try: | |
| 532 self.RunCommand('ls', [suri(src_bucket_uri, 'obj')]) | |
| 533 except CommandException, e: | |
| 534 self.assertIn('matched no objects', e.reason) | |
| 535 | |
| 536 def testLsBucketNonRecursive(self): | |
| 537 """Test that ls of a bucket returns expected results.""" | |
| 538 src_bucket_uri = self.CreateBucket(test_objects=['foo1', 'd0/foo2', | |
| 539 'd1/d2/foo3']) | |
| 540 output = self.RunCommand('ls', [suri(src_bucket_uri, '*')], | |
| 541 return_stdout=True) | |
| 542 expected = set([suri(src_bucket_uri, 'foo1'), | |
| 543 suri(src_bucket_uri, 'd1', ':'), | |
| 544 suri(src_bucket_uri, 'd1', 'd2') + src_bucket_uri.delim, | |
| 545 suri(src_bucket_uri, 'd0', ':'), | |
| 546 suri(src_bucket_uri, 'd0', 'foo2')]) | |
| 547 expected.add('') # Blank line between subdir listings. | |
| 548 actual = set(output.split('\n')) | |
| 549 self.assertEqual(expected, actual) | |
| 550 | |
| 551 def testLsBucketRecursive(self): | |
| 552 """Test that ls -R of a bucket returns expected results.""" | |
| 553 src_bucket_uri = self.CreateBucket(test_objects=['foo1', 'd0/foo2', | |
| 554 'd1/d2/foo3']) | |
| 555 output = self.RunCommand('ls', ['-R', suri(src_bucket_uri, '*')], | |
| 556 return_stdout=True) | |
| 557 expected = set([suri(src_bucket_uri, 'foo1'), | |
| 558 suri(src_bucket_uri, 'd1', ':'), | |
| 559 suri(src_bucket_uri, 'd1', 'd2', ':'), | |
| 560 suri(src_bucket_uri, 'd1', 'd2', 'foo3'), | |
| 561 suri(src_bucket_uri, 'd0', ':'), | |
| 562 suri(src_bucket_uri, 'd0', 'foo2')]) | |
| 563 expected.add('') # Blank line between subdir listings. | |
| 564 actual = set(output.split('\n')) | |
| 565 self.assertEqual(expected, actual) | |
| 566 | |
| 567 def testLsBucketRecursiveWithLeadingSlashObjectName(self): | |
| 568 """Test that ls -R of a bucket with an object that has leading slash.""" | |
| 569 dst_bucket_uri = self.CreateBucket(test_objects=['f0']) | |
| 570 output = self.RunCommand('ls', ['-R', suri(dst_bucket_uri) + '*'], | |
| 571 return_stdout=True) | |
| 572 expected = set([suri(dst_bucket_uri, 'f0')]) | |
| 573 expected.add('') # Blank line between subdir listings. | |
| 574 actual = set(output.split('\n')) | |
| 575 self.assertEqual(expected, actual) | |
| 576 | |
| 577 def testLsBucketSubdirNonRecursive(self): | |
| 578 """Test that ls of a bucket subdir returns expected results.""" | |
| 579 src_bucket_uri = self.CreateBucket(test_objects=['src_subdir/foo', | |
| 580 'src_subdir/nested/foo2']) | |
| 581 output = self.RunCommand('ls', [suri(src_bucket_uri, 'src_subdir')], | |
| 582 return_stdout=True) | |
| 583 expected = set([ | |
| 584 suri(src_bucket_uri, 'src_subdir', 'foo'), | |
| 585 suri(src_bucket_uri, 'src_subdir', 'nested') + src_bucket_uri.delim]) | |
| 586 expected.add('') # Blank line between subdir listings. | |
| 587 actual = set(output.split('\n')) | |
| 588 self.assertEqual(expected, actual) | |
| 589 | |
| 590 def testLsBucketSubdirRecursive(self): | |
| 591 """Test that ls -R of a bucket subdir returns expected results.""" | |
| 592 src_bucket_uri = self.CreateBucket(test_objects=['src_subdir/foo', | |
| 593 'src_subdir/nested/foo2']) | |
| 594 for final_char in ('/', ''): | |
| 595 output = self.RunCommand( | |
| 596 'ls', ['-R', suri(src_bucket_uri, 'src_subdir') + final_char], | |
| 597 return_stdout=True) | |
| 598 expected = set([ | |
| 599 suri(src_bucket_uri, 'src_subdir', ':'), | |
| 600 suri(src_bucket_uri, 'src_subdir', 'foo'), | |
| 601 suri(src_bucket_uri, 'src_subdir', 'nested', ':'), | |
| 602 suri(src_bucket_uri, 'src_subdir', 'nested', 'foo2')]) | |
| 603 expected.add('') # Blank line between subdir listings. | |
| 604 actual = set(output.split('\n')) | |
| 605 self.assertEqual(expected, actual) | |
| 606 | |
| 607 def testSetAclOnBucketRuns(self): | |
| 608 """Test that the 'acl set' command basically runs.""" | |
| 609 # We don't test reading back the acl (via 'acl get' command) because at | |
| 610 # present MockStorageService doesn't translate canned ACLs into actual ACL | |
| 611 # XML. | |
| 612 src_bucket_uri = self.CreateBucket() | |
| 613 self.RunCommand('acl', ['set', 'private', suri(src_bucket_uri)]) | |
| 614 | |
| 615 def testSetAclOnWildcardNamedBucketRuns(self): | |
| 616 """Test that 'acl set' basically runs against wildcard-named bucket.""" | |
| 617 # We don't test reading back the acl (via 'acl get' command) because at | |
| 618 # present MockStorageService doesn't translate canned ACLs into actual ACL | |
| 619 # XML. | |
| 620 src_bucket_uri = self.CreateBucket(test_objects=['f0']) | |
| 621 self.RunCommand('acl', ['set', 'private', suri(src_bucket_uri)[:-2] + '*']) | |
| 622 | |
| 623 def testSetAclOnObjectRuns(self): | |
| 624 """Test that the 'acl set' command basically runs.""" | |
| 625 src_bucket_uri = self.CreateBucket(test_objects=['f0']) | |
| 626 self.RunCommand('acl', ['set', 'private', suri(src_bucket_uri, '*')]) | |
| 627 | |
| 628 def testSetDefAclOnBucketRuns(self): | |
| 629 """Test that the 'defacl set' command basically runs.""" | |
| 630 src_bucket_uri = self.CreateBucket() | |
| 631 self.RunCommand('defacl', ['set', 'private', suri(src_bucket_uri)]) | |
| 632 | |
| 633 def testSetDefAclOnObjectFails(self): | |
| 634 """Test that the 'defacl set' command fails when run against an object.""" | |
| 635 src_bucket_uri = self.CreateBucket() | |
| 636 try: | |
| 637 self.RunCommand('defacl', ['set', 'private', suri(src_bucket_uri, '*')]) | |
| 638 self.fail('Did not get expected CommandException') | |
| 639 except CommandException, e: | |
| 640 self.assertIn('URL must name a bucket', e.reason) | |
| 641 | |
| 642 # @PerformsFileToObjectUpload | |
| 643 def testMinusDOptionWorks(self): | |
| 644 """Tests using gsutil -D option.""" | |
| 645 src_file = self.CreateTempFile(file_name='f0') | |
| 646 dst_bucket_uri = self.CreateBucket() | |
| 647 self.RunCommand('cp', [src_file, suri(dst_bucket_uri)], debug=3) | |
| 648 actual = list(self._test_wildcard_iterator( | |
| 649 suri(dst_bucket_uri, '*')).IterAll(expand_top_level_buckets=True)) | |
| 650 self.assertEqual(1, len(actual)) | |
| 651 self.assertEqual('f0', actual[0].root_object.name) | |
| 652 | |
| 653 def DownloadTestHelper(self, func): | |
| 654 """Test resumable download with custom test function. | |
| 655 | |
| 656 The custom function distorts downloaded data. We expect an exception to be | |
| 657 raised and the dest file to be removed. | |
| 658 | |
| 659 Args: | |
| 660 func: Custom test function used to distort the downloaded data. | |
| 661 """ | |
| 662 object_uri = self.CreateObject(contents='foo') | |
| 663 # Need to explicitly tell the key to populate its etag so that hash | |
| 664 # validation will be performed. | |
| 665 object_uri.get_key().set_etag() | |
| 666 dst_dir = self.CreateTempDir() | |
| 667 got_expected_exception = False | |
| 668 try: | |
| 669 self.RunCommand('cp', [suri(object_uri), dst_dir], test_method=func) | |
| 670 self.fail('Did not get expected CommandException') | |
| 671 except HashMismatchException: | |
| 672 self.assertFalse(os.listdir(dst_dir)) | |
| 673 got_expected_exception = True | |
| 674 except Exception, e: | |
| 675 self.fail('Unexpected exception raised: %s' % e) | |
| 676 if not got_expected_exception: | |
| 677 self.fail('Did not get expected CommandException') | |
| 678 | |
| 679 def testDownloadWithObjectSizeChange(self): | |
| 680 """Test resumable download on an object that changes size. | |
| 681 | |
| 682 Size change occurs before the downloaded file's checksum is validated. | |
| 683 """ | |
| 684 self.DownloadTestHelper(_Append) | |
| 685 | |
| 686 def testDownloadWithFileContentChange(self): | |
| 687 """Tests resumable download on an object that changes content. | |
| 688 | |
| 689 Content change occurs before the downloaded file's checksum is validated. | |
| 690 """ | |
| 691 self.DownloadTestHelper(_Overwrite) | |
| 692 | |
| 693 # @PerformsFileToObjectUpload | |
| 694 def testFlatCopyingObjsAndFilesToBucketSubDir(self): | |
| 695 """Tests copying flatly listed objects and files to bucket subdir.""" | |
| 696 src_bucket_uri = self.CreateBucket(test_objects=['f0', 'd0/f1', 'd1/d2/f2']) | |
| 697 src_dir = self.CreateTempDir(test_files=['f3', ('d3', 'f4'), | |
| 698 ('d4', 'd5', 'f5')]) | |
| 699 dst_bucket_uri = self.CreateBucket(test_objects=['dst_subdir0/existing', | |
| 700 'dst_subdir1/existing']) | |
| 701 # Test with and without final slash on dest subdir. | |
| 702 for i, final_char in enumerate(('/', '')): | |
| 703 self.RunCommand( | |
| 704 'cp', ['-R', suri(src_bucket_uri, '**'), os.path.join(src_dir, '**'), | |
| 705 suri(dst_bucket_uri, 'dst_subdir%d' % i) + final_char]) | |
| 706 | |
| 707 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 708 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 709 expected = set() | |
| 710 for i in range(2): | |
| 711 expected.add(suri(dst_bucket_uri, 'dst_subdir%d' % i, 'existing')) | |
| 712 for j in range(6): | |
| 713 expected.add(suri(dst_bucket_uri, 'dst_subdir%d' % i, 'f%d' % j)) | |
| 714 self.assertEqual(expected, actual) | |
| 715 | |
| 716 # @PerformsFileToObjectUpload | |
| 717 def testRecursiveCopyObjsAndFilesToExistingBucketSubDir(self): | |
| 718 """Tests recursive copy of objects and files to existing bucket subdir.""" | |
| 719 src_bucket_uri = self.CreateBucket(test_objects=['f0', 'nested/f1']) | |
| 720 dst_bucket_uri = self.CreateBucket(test_objects=[ | |
| 721 'dst_subdir0/existing_obj', 'dst_subdir1/existing_obj']) | |
| 722 src_dir = self.CreateTempDir(test_files=['f2', ('nested', 'f3')]) | |
| 723 # Test with and without final slash on dest subdir. | |
| 724 for i, final_char in enumerate(('/', '')): | |
| 725 self.RunCommand( | |
| 726 'cp', ['-R', suri(src_bucket_uri), src_dir, | |
| 727 suri(dst_bucket_uri, 'dst_subdir%d' % i) + final_char]) | |
| 728 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 729 suri(dst_bucket_uri, 'dst_subdir%d' % i, '**')).IterAll( | |
| 730 expand_top_level_buckets=True)) | |
| 731 tmp_dirname = os.path.split(src_dir)[1] | |
| 732 bucketname = src_bucket_uri.bucket_name | |
| 733 expected = set([ | |
| 734 suri(dst_bucket_uri, 'dst_subdir%d' % i, 'existing_obj'), | |
| 735 suri(dst_bucket_uri, 'dst_subdir%d' % i, bucketname, 'f0'), | |
| 736 suri(dst_bucket_uri, 'dst_subdir%d' % i, bucketname, 'nested', 'f1'), | |
| 737 suri(dst_bucket_uri, 'dst_subdir%d' % i, tmp_dirname, 'f2'), | |
| 738 suri(dst_bucket_uri, 'dst_subdir%d' % i, tmp_dirname, 'nested', 'f3') | |
| 739 ]) | |
| 740 self.assertEqual(expected, actual) | |
| 741 | |
| 742 # @PerformsFileToObjectUpload | |
| 743 def testRecursiveCopyObjsAndFilesToNonExistentBucketSubDir(self): | |
| 744 """Tests recursive copy of objs + files to non-existent bucket subdir.""" | |
| 745 src_bucket_uri = self.CreateBucket(test_objects=['f0', 'nested/f1']) | |
| 746 src_dir = self.CreateTempDir(test_files=['f2', ('nested', 'f3')]) | |
| 747 dst_bucket_uri = self.CreateBucket() | |
| 748 self.RunCommand('cp', ['-R', src_dir, suri(src_bucket_uri), | |
| 749 suri(dst_bucket_uri, 'dst_subdir')]) | |
| 750 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 751 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 752 expected = set([suri(dst_bucket_uri, 'dst_subdir', 'f0'), | |
| 753 suri(dst_bucket_uri, 'dst_subdir', 'nested', 'f1'), | |
| 754 suri(dst_bucket_uri, 'dst_subdir', 'f2'), | |
| 755 suri(dst_bucket_uri, 'dst_subdir', 'nested', 'f3')]) | |
| 756 self.assertEqual(expected, actual) | |
| 757 | |
| 758 def testCopyingBucketSubDirToDir(self): | |
| 759 """Tests copying a bucket subdir to a directory.""" | |
| 760 src_bucket_uri = self.CreateBucket(test_objects=['src_subdir/obj']) | |
| 761 dst_dir = self.CreateTempDir() | |
| 762 # Test with and without final slash on dest subdir. | |
| 763 for (final_src_char, final_dst_char) in ( | |
| 764 ('', ''), ('', '/'), ('/', ''), ('/', '/')): | |
| 765 # Mock objects don't support hash digestion. | |
| 766 with SetBotoConfigForTest([('GSUtil', 'check_hashes', 'never')]): | |
| 767 self.RunCommand( | |
| 768 'cp', ['-R', suri(src_bucket_uri, 'src_subdir') + final_src_char, | |
| 769 dst_dir + final_dst_char]) | |
| 770 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 771 '%s%s**' % (dst_dir, os.sep)).IterAll(expand_top_level_buckets=True)) | |
| 772 expected = set([suri(dst_dir, 'src_subdir', 'obj')]) | |
| 773 self.assertEqual(expected, actual) | |
| 774 | |
| 775 def testCopyingWildcardSpecifiedBucketSubDirToExistingDir(self): | |
| 776 """Tests copying a wildcard-specified bucket subdir to a directory.""" | |
| 777 src_bucket_uri = self.CreateBucket( | |
| 778 test_objects=['src_sub0dir/foo', 'src_sub1dir/foo', 'src_sub2dir/foo', | |
| 779 'src_sub3dir/foo']) | |
| 780 dst_dir = self.CreateTempDir() | |
| 781 # Test with and without final slash on dest subdir. | |
| 782 for i, (final_src_char, final_dst_char) in enumerate(( | |
| 783 ('', ''), ('', '/'), ('/', ''), ('/', '/'))): | |
| 784 # Mock objects don't support hash digestion. | |
| 785 with SetBotoConfigForTest([('GSUtil', 'check_hashes', 'never')]): | |
| 786 self.RunCommand( | |
| 787 'cp', ['-R', suri(src_bucket_uri, 'src_sub%d*' % i) + | |
| 788 final_src_char, dst_dir + final_dst_char]) | |
| 789 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 790 os.path.join(dst_dir, 'src_sub%ddir' % i, '**')).IterAll( | |
| 791 expand_top_level_buckets=True)) | |
| 792 expected = set([suri(dst_dir, 'src_sub%ddir' % i, 'foo')]) | |
| 793 self.assertEqual(expected, actual) | |
| 794 | |
| 795 def testCopyingBucketSubDirToDirFailsWithoutMinusR(self): | |
| 796 """Tests for failure when attempting bucket subdir copy without -R.""" | |
| 797 src_bucket_uri = self.CreateBucket(test_objects=['src_subdir/obj']) | |
| 798 dst_dir = self.CreateTempDir() | |
| 799 try: | |
| 800 self.RunCommand( | |
| 801 'cp', [suri(src_bucket_uri, 'src_subdir'), dst_dir]) | |
| 802 self.fail('Did not get expected CommandException') | |
| 803 except CommandException, e: | |
| 804 self.assertIn('No URLs matched', e.reason) | |
| 805 | |
| 806 def testCopyingBucketSubDirToBucketSubDir(self): | |
| 807 """Tests copying a bucket subdir to another bucket subdir.""" | |
| 808 src_bucket_uri = self.CreateBucket( | |
| 809 test_objects=['src_subdir_%d/obj' % i for i in range(4)]) | |
| 810 dst_bucket_uri = self.CreateBucket( | |
| 811 test_objects=['dst_subdir_%d/obj2' % i for i in range(4)]) | |
| 812 # Test with and without final slash on dest subdir. | |
| 813 for i, (final_src_char, final_dst_char) in enumerate(( | |
| 814 ('', ''), ('', '/'), ('/', ''), ('/', '/'))): | |
| 815 self.RunCommand( | |
| 816 'cp', ['-R', | |
| 817 suri(src_bucket_uri, 'src_subdir_%d' % i) + final_src_char, | |
| 818 suri(dst_bucket_uri, 'dst_subdir_%d' % i) + final_dst_char]) | |
| 819 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 820 suri(dst_bucket_uri, 'dst_subdir_%d' % i, '**')).IterAll( | |
| 821 expand_top_level_buckets=True)) | |
| 822 expected = set([suri(dst_bucket_uri, 'dst_subdir_%d' % i, | |
| 823 'src_subdir_%d' % i, 'obj'), | |
| 824 suri(dst_bucket_uri, 'dst_subdir_%d' % i, 'obj2')]) | |
| 825 self.assertEqual(expected, actual) | |
| 826 | |
| 827 def testCopyingBucketSubDirToBucketSubDirWithNested(self): | |
| 828 """Tests copying a bucket subdir to another bucket subdir with nesting.""" | |
| 829 src_bucket_uri = self.CreateBucket( | |
| 830 test_objects=['src_subdir_%d/obj' % i for i in range(4)] + | |
| 831 ['src_subdir_%d/nested/obj' % i for i in range(4)]) | |
| 832 dst_bucket_uri = self.CreateBucket( | |
| 833 test_objects=['dst_subdir_%d/obj2' % i for i in range(4)]) | |
| 834 # Test with and without final slash on dest subdir. | |
| 835 for i, (final_src_char, final_dst_char) in enumerate(( | |
| 836 ('', ''), ('', '/'), ('/', ''), ('/', '/'))): | |
| 837 self.RunCommand( | |
| 838 'cp', ['-R', | |
| 839 suri(src_bucket_uri, 'src_subdir_%d' % i) + final_src_char, | |
| 840 suri(dst_bucket_uri, 'dst_subdir_%d' % i) + final_dst_char]) | |
| 841 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 842 suri(dst_bucket_uri, 'dst_subdir_%d' % i, '**')).IterAll( | |
| 843 expand_top_level_buckets=True)) | |
| 844 expected = set([suri(dst_bucket_uri, 'dst_subdir_%d' % i, | |
| 845 'src_subdir_%d' % i, 'obj'), | |
| 846 suri(dst_bucket_uri, 'dst_subdir_%d' % i, | |
| 847 'src_subdir_%d' % i, 'nested', 'obj'), | |
| 848 suri(dst_bucket_uri, 'dst_subdir_%d' % i, 'obj2')]) | |
| 849 self.assertEqual(expected, actual) | |
| 850 | |
| 851 def testMovingBucketSubDirToExistingBucketSubDir(self): | |
| 852 """Tests moving a bucket subdir to a existing bucket subdir.""" | |
| 853 src_objs = ['foo'] | |
| 854 for i in range(4): | |
| 855 src_objs.extend(['src_subdir%d/foo2' % i, 'src_subdir%d/nested/foo3' % i]) | |
| 856 src_bucket_uri = self.CreateBucket(test_objects=src_objs) | |
| 857 dst_bucket_uri = self.CreateBucket( | |
| 858 test_objects=['dst_subdir%d/existing' % i for i in range(4)]) | |
| 859 # Test with and without final slash on dest subdir. | |
| 860 for i, (final_src_char, final_dst_char) in enumerate(( | |
| 861 ('', ''), ('', '/'), ('/', ''), ('/', '/'))): | |
| 862 self.RunCommand( | |
| 863 'mv', [suri(src_bucket_uri, 'src_subdir%d' % i) + final_src_char, | |
| 864 suri(dst_bucket_uri, 'dst_subdir%d' % i) + final_dst_char]) | |
| 865 | |
| 866 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 867 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 868 expected = set() | |
| 869 for i in range(4): | |
| 870 expected.add(suri(dst_bucket_uri, 'dst_subdir%d' % i, 'existing')) | |
| 871 expected.add(suri(dst_bucket_uri, 'dst_subdir%d' % i, 'src_subdir%d' %i, | |
| 872 'foo2')) | |
| 873 expected.add(suri(dst_bucket_uri, 'dst_subdir%d' % i, 'src_subdir%d' %i, | |
| 874 'nested', 'foo3')) | |
| 875 self.assertEqual(expected, actual) | |
| 876 | |
| 877 def testCopyingObjectToBucketSubDir(self): | |
| 878 """Tests copying an object to a bucket subdir.""" | |
| 879 src_bucket_uri = self.CreateBucket(test_objects=['obj0']) | |
| 880 dst_bucket_uri = self.CreateBucket(test_objects=['dir0/existing', | |
| 881 'dir1/existing']) | |
| 882 # Test with and without final slash on dest subdir. | |
| 883 for i, final_dst_char in enumerate(('', '/')): | |
| 884 self.RunCommand('cp', [ | |
| 885 suri(src_bucket_uri, 'obj0'), | |
| 886 suri(dst_bucket_uri, 'dir%d' % i) + final_dst_char]) | |
| 887 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 888 suri(dst_bucket_uri, 'dir%d' % i, '**')).IterAll( | |
| 889 expand_top_level_buckets=True)) | |
| 890 expected = set([suri(dst_bucket_uri, 'dir%d' % i, 'obj0'), | |
| 891 suri(dst_bucket_uri, 'dir%d' % i, 'existing')]) | |
| 892 self.assertEqual(expected, actual) | |
| 893 | |
| 894 # @PerformsFileToObjectUpload | |
| 895 def testCopyingWildcardedFilesToBucketSubDir(self): | |
| 896 """Tests copying wildcarded files to a bucket subdir.""" | |
| 897 dst_bucket_uri = self.CreateBucket(test_objects=['subdir0/existing', | |
| 898 'subdir1/existing']) | |
| 899 src_dir = self.CreateTempDir(test_files=['f0', 'f1', 'f2']) | |
| 900 # Test with and without final slash on dest subdir. | |
| 901 for i, final_dst_char in enumerate(('', '/')): | |
| 902 self.RunCommand( | |
| 903 'cp', [os.path.join(src_dir, 'f?'), | |
| 904 suri(dst_bucket_uri, 'subdir%d' % i) + final_dst_char]) | |
| 905 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 906 suri(dst_bucket_uri, 'subdir%d' % i, '**')).IterAll( | |
| 907 expand_top_level_buckets=True)) | |
| 908 expected = set([suri(dst_bucket_uri, 'subdir%d' % i, 'existing'), | |
| 909 suri(dst_bucket_uri, 'subdir%d' % i, 'f0'), | |
| 910 suri(dst_bucket_uri, 'subdir%d' % i, 'f1'), | |
| 911 suri(dst_bucket_uri, 'subdir%d' % i, 'f2')]) | |
| 912 self.assertEqual(expected, actual) | |
| 913 | |
| 914 # @PerformsFileToObjectUpload | |
| 915 def testCopyingOneNestedFileToBucketSubDir(self): | |
| 916 """Tests copying one nested file to a bucket subdir.""" | |
| 917 dst_bucket_uri = self.CreateBucket(test_objects=['d0/placeholder', | |
| 918 'd1/placeholder']) | |
| 919 src_dir = self.CreateTempDir(test_files=[('d3', 'd4', 'nested', 'f1')]) | |
| 920 # Test with and without final slash on dest subdir. | |
| 921 for i, final_dst_char in enumerate(('', '/')): | |
| 922 self.RunCommand('cp', ['-r', suri(src_dir, 'd3'), | |
| 923 suri(dst_bucket_uri, 'd%d' % i) + final_dst_char]) | |
| 924 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 925 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 926 expected = set([ | |
| 927 suri(dst_bucket_uri, 'd0', 'placeholder'), | |
| 928 suri(dst_bucket_uri, 'd1', 'placeholder'), | |
| 929 suri(dst_bucket_uri, 'd0', 'd3', 'd4', 'nested', 'f1'), | |
| 930 suri(dst_bucket_uri, 'd1', 'd3', 'd4', 'nested', 'f1')]) | |
| 931 self.assertEqual(expected, actual) | |
| 932 | |
| 933 def testMovingWildcardedFilesToNonExistentBucketSubDir(self): | |
| 934 """Tests moving files to a non-existent bucket subdir.""" | |
| 935 # This tests for how we allow users to do something like: | |
| 936 # gsutil cp *.txt gs://bucket/dir | |
| 937 # where *.txt matches more than 1 file and gs://bucket/dir | |
| 938 # doesn't exist as a subdir. | |
| 939 # | |
| 940 src_bucket_uri = self.CreateBucket(test_objects=[ | |
| 941 'f0f0', 'f0f1', 'f1f0', 'f1f1']) | |
| 942 dst_bucket_uri = self.CreateBucket(test_objects=[ | |
| 943 'dst_subdir0/existing_obj', 'dst_subdir1/existing_obj']) | |
| 944 # Test with and without final slash on dest subdir. | |
| 945 for i, final_dst_char in enumerate(('', '/')): | |
| 946 # Copy some files into place in dst bucket. | |
| 947 self.RunCommand( | |
| 948 'cp', [suri(src_bucket_uri, 'f%df*' % i), | |
| 949 suri(dst_bucket_uri, 'dst_subdir%d' % i) + final_dst_char]) | |
| 950 # Now do the move test. | |
| 951 self.RunCommand( | |
| 952 'mv', [suri(src_bucket_uri, 'f%d*' % i), | |
| 953 suri(dst_bucket_uri, 'nonexisting%d' % i) + final_dst_char]) | |
| 954 | |
| 955 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 956 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 957 expected = set([ | |
| 958 suri(dst_bucket_uri, 'dst_subdir0', 'existing_obj'), | |
| 959 suri(dst_bucket_uri, 'dst_subdir0', 'f0f0'), | |
| 960 suri(dst_bucket_uri, 'dst_subdir0', 'f0f1'), | |
| 961 suri(dst_bucket_uri, 'nonexisting0', 'f0f0'), | |
| 962 suri(dst_bucket_uri, 'nonexisting0', 'f0f1'), | |
| 963 suri(dst_bucket_uri, 'dst_subdir1', 'existing_obj'), | |
| 964 suri(dst_bucket_uri, 'dst_subdir1', 'f1f0'), | |
| 965 suri(dst_bucket_uri, 'dst_subdir1', 'f1f1'), | |
| 966 suri(dst_bucket_uri, 'nonexisting1', 'f1f0'), | |
| 967 suri(dst_bucket_uri, 'nonexisting1', 'f1f1')]) | |
| 968 self.assertEqual(expected, actual) | |
| 969 | |
| 970 def testMovingObjectToBucketSubDir(self): | |
| 971 """Tests moving an object to a bucket subdir.""" | |
| 972 src_bucket_uri = self.CreateBucket(test_objects=['obj0', 'obj1']) | |
| 973 dst_bucket_uri = self.CreateBucket(test_objects=[ | |
| 974 'dst_subdir0/existing_obj', 'dst_subdir1/existing_obj']) | |
| 975 # Test with and without final slash on dest subdir. | |
| 976 for i, final_dst_char in enumerate(('', '/')): | |
| 977 self.RunCommand( | |
| 978 'mv', [suri(src_bucket_uri, 'obj%d' % i), | |
| 979 suri(dst_bucket_uri, 'dst_subdir%d' % i) + final_dst_char]) | |
| 980 | |
| 981 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 982 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 983 expected = set([ | |
| 984 suri(dst_bucket_uri, 'dst_subdir0', 'existing_obj'), | |
| 985 suri(dst_bucket_uri, 'dst_subdir0', 'obj0'), | |
| 986 suri(dst_bucket_uri, 'dst_subdir1', 'existing_obj'), | |
| 987 suri(dst_bucket_uri, 'dst_subdir1', 'obj1')]) | |
| 988 self.assertEqual(expected, actual) | |
| 989 | |
| 990 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 991 suri(src_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 992 self.assertEqual(actual, set()) | |
| 993 | |
| 994 def testWildcardSrcSubDirMoveDisallowed(self): | |
| 995 """Tests moving a bucket subdir specified by wildcard is disallowed.""" | |
| 996 src_bucket_uri = self.CreateBucket(test_objects=['dir/foo1']) | |
| 997 dst_bucket_uri = self.CreateBucket(test_objects=['dir/foo2']) | |
| 998 try: | |
| 999 self.RunCommand( | |
| 1000 'mv', [suri(src_bucket_uri, 'dir*'), suri(dst_bucket_uri, 'dir')]) | |
| 1001 self.fail('Did not get expected CommandException') | |
| 1002 except CommandException, e: | |
| 1003 self.assertIn('mv command disallows naming', e.reason) | |
| 1004 | |
| 1005 def testMovingBucketSubDirToNonExistentBucketSubDir(self): | |
| 1006 """Tests moving a bucket subdir to a non-existent bucket subdir.""" | |
| 1007 src_bucket = self.CreateBucket(test_objects=[ | |
| 1008 'foo', 'src_subdir0/foo2', 'src_subdir0/nested/foo3', | |
| 1009 'src_subdir1/foo2', 'src_subdir1/nested/foo3']) | |
| 1010 dst_bucket = self.CreateBucket() | |
| 1011 # Test with and without final slash on dest subdir. | |
| 1012 for i, final_src_char in enumerate(('', '/')): | |
| 1013 self.RunCommand( | |
| 1014 'mv', [suri(src_bucket, 'src_subdir%d' % i) + final_src_char, | |
| 1015 suri(dst_bucket, 'dst_subdir%d' % i)]) | |
| 1016 | |
| 1017 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 1018 suri(dst_bucket, '**')).IterAll(expand_top_level_buckets=True)) | |
| 1019 # Unlike the case with copying, with mv we expect renaming to occur | |
| 1020 # at the level of the src subdir, vs appending that subdir beneath the | |
| 1021 # dst subdir like is done for copying. | |
| 1022 expected = set([suri(dst_bucket, 'dst_subdir0', 'foo2'), | |
| 1023 suri(dst_bucket, 'dst_subdir1', 'foo2'), | |
| 1024 suri(dst_bucket, 'dst_subdir0', 'nested', 'foo3'), | |
| 1025 suri(dst_bucket, 'dst_subdir1', 'nested', 'foo3')]) | |
| 1026 self.assertEqual(expected, actual) | |
| 1027 | |
| 1028 def testRemovingBucketSubDir(self): | |
| 1029 """Tests removing a bucket subdir.""" | |
| 1030 dst_bucket_uri = self.CreateBucket(test_objects=[ | |
| 1031 'f0', 'dir0/f1', 'dir0/nested/f2', 'dir1/f1', 'dir1/nested/f2']) | |
| 1032 # Test with and without final slash on dest subdir. | |
| 1033 for i, final_src_char in enumerate(('', '/')): | |
| 1034 # Test removing bucket subdir. | |
| 1035 self.RunCommand( | |
| 1036 'rm', ['-R', suri(dst_bucket_uri, 'dir%d' % i) + final_src_char]) | |
| 1037 actual = set(str(u) for u in self._test_wildcard_iterator( | |
| 1038 suri(dst_bucket_uri, '**')).IterAll(expand_top_level_buckets=True)) | |
| 1039 expected = set([suri(dst_bucket_uri, 'f0')]) | |
| 1040 self.assertEqual(expected, actual) | |
| 1041 | |
| 1042 def testRecursiveRemoveObjsInBucket(self): | |
| 1043 """Tests removing all objects in bucket via rm -R gs://bucket.""" | |
| 1044 bucket_uris = [ | |
| 1045 self.CreateBucket(test_objects=['f0', 'dir/f1', 'dir/nested/f2']), | |
| 1046 self.CreateBucket(test_objects=['f0', 'dir/f1', 'dir/nested/f2'])] | |
| 1047 # Test with and without final slash on dest subdir. | |
| 1048 for i, final_src_char in enumerate(('', '/')): | |
| 1049 # Test removing all objects via rm -R. | |
| 1050 self.RunCommand('rm', ['-R', suri(bucket_uris[i]) + final_src_char]) | |
| 1051 try: | |
| 1052 self.RunCommand('ls', [suri(bucket_uris[i])]) | |
| 1053 # Ensure exception is raised. | |
| 1054 self.assertTrue(False) | |
| 1055 except NotFoundException, e: | |
| 1056 self.assertEqual(e.status, 404) | |
| 1057 | |
| 1058 def testUnicodeArgs(self): | |
| 1059 """Tests that you can list an object with unicode characters.""" | |
| 1060 object_name = u'フォ' | |
| 1061 bucket_uri = self.CreateBucket() | |
| 1062 self.CreateObject(bucket_uri=bucket_uri, object_name=object_name, | |
| 1063 contents='foo') | |
| 1064 object_name_bytes = object_name.encode(UTF8) | |
| 1065 stdout = self.RunCommand('ls', [suri(bucket_uri, object_name_bytes)], | |
| 1066 return_stdout=True) | |
| 1067 self.assertIn(object_name_bytes, stdout) | |
| 1068 | |
| 1069 def testRecursiveListTrailingSlash(self): | |
| 1070 bucket_uri = self.CreateBucket() | |
| 1071 obj_uri = self.CreateObject( | |
| 1072 bucket_uri=bucket_uri, object_name='/', contents='foo') | |
| 1073 stdout = self.RunCommand('ls', ['-R', suri(bucket_uri)], return_stdout=True) | |
| 1074 # Note: The suri function normalizes the URI, so the double slash gets | |
| 1075 # removed. | |
| 1076 self.assertEqual(stdout.splitlines(), [suri(obj_uri) + '/:', | |
| 1077 suri(obj_uri) + '/']) | |
| 1078 | |
| 1079 def FinalObjNameComponent(self, uri): | |
| 1080 """For gs://bucket/abc/def/ghi returns ghi.""" | |
| 1081 return uri.uri.rpartition('/')[-1] | |
| 1082 | |
| 1083 def testFileContainingColon(self): | |
| 1084 url_str = 'abc:def' | |
| 1085 url = StorageUrlFromString(url_str) | |
| 1086 self.assertEqual('file', url.scheme) | |
| 1087 self.assertEqual('file://%s' % url_str, url.url_string) | |
| 1088 | |
| 1089 | |
| 1090 # TODO: These should all be moved to their own test_*.py testing files. | |
| 1091 class GsUtilCommandTests(testcase.GsUtilUnitTestCase): | |
| 1092 """Basic sanity check tests to make sure commands run.""" | |
| 1093 | |
| 1094 def testDisableLoggingCommandRuns(self): | |
| 1095 """Test that the 'logging set off' command basically runs.""" | |
| 1096 src_bucket_uri = self.CreateBucket() | |
| 1097 self.RunCommand('logging', ['set', 'off', suri(src_bucket_uri)]) | |
| 1098 | |
| 1099 def testEnableLoggingCommandRuns(self): | |
| 1100 """Test that the 'logging set on' command basically runs.""" | |
| 1101 src_bucket_uri = self.CreateBucket() | |
| 1102 self.RunCommand('logging', ['set', 'on', '-b', 'gs://log_bucket', | |
| 1103 suri(src_bucket_uri)]) | |
| 1104 | |
| 1105 def testHelpCommandDoesntRaise(self): | |
| 1106 """Test that the help command doesn't raise (sanity checks all help).""" | |
| 1107 # Unset PAGER if defined, so help output paginating into $PAGER doesn't | |
| 1108 # cause test to pause. | |
| 1109 if 'PAGER' in os.environ: | |
| 1110 del os.environ['PAGER'] | |
| 1111 self.RunCommand('help', []) | |
| 1112 | |
| 1113 def testCatCommandRuns(self): | |
| 1114 """Test that the cat command basically runs.""" | |
| 1115 src_uri = self.CreateObject(contents='foo') | |
| 1116 stdout = self.RunCommand('cat', [suri(src_uri)], return_stdout=True) | |
| 1117 self.assertEqual(stdout, 'foo') | |
| 1118 | |
| 1119 def testGetLoggingCommandRuns(self): | |
| 1120 """Test that the 'logging get' command basically runs.""" | |
| 1121 src_bucket_uri = self.CreateBucket() | |
| 1122 self.RunCommand('logging', ['get', suri(src_bucket_uri)]) | |
| 1123 | |
| 1124 def testMakeBucketsCommand(self): | |
| 1125 """Test mb on existing bucket.""" | |
| 1126 dst_bucket_uri = self.CreateBucket() | |
| 1127 try: | |
| 1128 self.RunCommand('mb', [suri(dst_bucket_uri)]) | |
| 1129 self.fail('Did not get expected StorageCreateError') | |
| 1130 except ServiceException, e: | |
| 1131 self.assertEqual(e.status, 409) | |
| 1132 | |
| 1133 def testRemoveBucketsCommand(self): | |
| 1134 """Test rb on non-existent bucket.""" | |
| 1135 dst_bucket_uri = self.CreateBucket() | |
| 1136 try: | |
| 1137 self.RunCommand( | |
| 1138 'rb', ['gs://no_exist_%s' % dst_bucket_uri.bucket_name]) | |
| 1139 self.fail('Did not get expected NotFoundException') | |
| 1140 except NotFoundException, e: | |
| 1141 self.assertEqual(e.status, 404) | |
| 1142 | |
| 1143 def testRemoveObjsCommand(self): | |
| 1144 """Test rm command on non-existent object.""" | |
| 1145 dst_bucket_uri = self.CreateBucket() | |
| 1146 try: | |
| 1147 self.RunCommand('rm', [suri(dst_bucket_uri, 'non_existent')]) | |
| 1148 self.fail('Did not get expected CommandException') | |
| 1149 except CommandException, e: | |
| 1150 self.assertIn('No URLs matched', e.reason) | |
| 1151 | |
| 1152 # Now that gsutil ver computes a checksum it adds 1-3 seconds to test run | |
| 1153 # time (for in memory mocked tests that otherwise take ~ 0.1 seconds). Since | |
| 1154 # it provides very little test value, we're leaving this test commented out. | |
| 1155 # def testVerCommmandRuns(self): | |
| 1156 # """Test that the Ver command basically runs""" | |
| 1157 # self.RunCommand('ver', []) | |
| OLD | NEW |