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 |