OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf-8 -*- |
| 2 # Copyright 2013 Google Inc. All Rights Reserved. |
| 3 # |
| 4 # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 # you may not use this file except in compliance with the License. |
| 6 # You may obtain a copy of the License at |
| 7 # |
| 8 # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 # |
| 10 # Unless required by applicable law or agreed to in writing, software |
| 11 # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 # See the License for the specific language governing permissions and |
| 14 # limitations under the License. |
| 15 """Integration tests for rm command.""" |
| 16 |
| 17 from __future__ import absolute_import |
| 18 |
| 19 import re |
| 20 |
| 21 import gslib.tests.testcase as testcase |
| 22 from gslib.tests.testcase.base import MAX_BUCKET_LENGTH |
| 23 from gslib.tests.testcase.integration_testcase import SkipForS3 |
| 24 from gslib.tests.util import GenerationFromURI as urigen |
| 25 from gslib.tests.util import ObjectToURI as suri |
| 26 from gslib.util import Retry |
| 27 |
| 28 |
| 29 class TestRm(testcase.GsUtilIntegrationTestCase): |
| 30 """Integration tests for rm command.""" |
| 31 |
| 32 def _RunRemoveCommandAndCheck(self, command_and_args, objects_to_remove=None, |
| 33 buckets_to_remove=None, stdin=None): |
| 34 """Tests a remove command in the presence of eventual listing consistency. |
| 35 |
| 36 Eventual listing consistency means that a remove command may not see all |
| 37 of the objects to be removed at once. When removing multiple objects |
| 38 (or buckets via -r), some calls may return no matches and multiple calls |
| 39 to the rm command may be necessary to reach the desired state. This function |
| 40 retries the rm command, incrementally tracking what has been removed and |
| 41 ensuring that the exact set of objects/buckets are removed across all |
| 42 retried calls. |
| 43 |
| 44 The caller is responsible for confirming the existence of buckets/objects |
| 45 prior to calling this function. |
| 46 |
| 47 Args: |
| 48 command_and_args: List of strings representing the rm command+args to run. |
| 49 objects_to_remove: List of object URL strings (optionally including |
| 50 generation) that should be removed by the command, if any. |
| 51 buckets_to_remove: List of bucket URL strings that should be removed by |
| 52 the command, if any. |
| 53 stdin: String of data to pipe to the process as standard input (for |
| 54 testing -I option). |
| 55 """ |
| 56 cumulative_stderr_lines = set() |
| 57 bucket_strings = [] |
| 58 for bucket_to_remove in buckets_to_remove or []: |
| 59 bucket_strings.append('Removing %s/...' % bucket_to_remove) |
| 60 object_strings = [] |
| 61 for object_to_remove in objects_to_remove or []: |
| 62 object_strings.append('Removing %s...' % object_to_remove) |
| 63 expected_stderr_lines = set(object_strings + bucket_strings) |
| 64 |
| 65 @Retry(AssertionError, tries=5, timeout_secs=1) |
| 66 def _RunRmCommandAndCheck(): |
| 67 """Runs the command with retries, updating+checking cumulative output.""" |
| 68 stderr = self.RunGsUtil(command_and_args, return_stderr=True, |
| 69 expected_status=None, stdin=stdin) |
| 70 update_lines = True |
| 71 # Retry 404's and 409's due to eventual listing consistency, but don't add |
| 72 # the output to the set. |
| 73 if ('No URLs matched' in stderr or |
| 74 '409 BucketNotEmpty' in stderr or |
| 75 '409 VersionedBucketNotEmpty' in stderr): |
| 76 update_lines = False |
| 77 |
| 78 # For recursive deletes of buckets, it is possible that the bucket is |
| 79 # deleted before the objects are all present in the listing, in which case |
| 80 # we will never see all of the expected "Removing object..." messages. |
| 81 # Since this is still a successful outcome, just return successfully. |
| 82 if '-r' in command_and_args and 'bucket does not exist' in stderr: |
| 83 for bucket_to_remove in buckets_to_remove: |
| 84 matching_bucket = re.match(r'.*404\s+%s\s+bucket does not exist' % |
| 85 re.escape(bucket_to_remove), stderr) |
| 86 if matching_bucket: |
| 87 for line in cumulative_stderr_lines: |
| 88 if 'Removing %s/...' % bucket_to_remove in line: |
| 89 return |
| 90 if 'Removing %s/...' % bucket_to_remove in stderr: |
| 91 return |
| 92 |
| 93 if update_lines: |
| 94 cumulative_stderr_lines.update(set(stderr.splitlines())) |
| 95 |
| 96 # Ensure all of the expected strings are present. |
| 97 self.assertEqual(cumulative_stderr_lines, expected_stderr_lines) |
| 98 |
| 99 _RunRmCommandAndCheck() |
| 100 |
| 101 def test_all_versions_current(self): |
| 102 """Test that 'rm -a' for an object with a current version works.""" |
| 103 bucket_uri = self.CreateVersionedBucket() |
| 104 key_uri = bucket_uri.clone_replace_name('foo') |
| 105 key_uri.set_contents_from_string('bar') |
| 106 g1 = urigen(key_uri) |
| 107 key_uri.set_contents_from_string('baz') |
| 108 g2 = urigen(key_uri) |
| 109 self.AssertNObjectsInBucket(bucket_uri, 2, versioned=True) |
| 110 # Use @Retry as hedge against bucket listing eventual consistency. |
| 111 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 112 def _Check1(stderr_lines): |
| 113 stderr = self.RunGsUtil(['-m', 'rm', '-a', suri(key_uri)], |
| 114 return_stderr=True) |
| 115 stderr_lines.update(set(stderr.splitlines())) |
| 116 stderr = '\n'.join(stderr_lines) |
| 117 self.assertEqual(stderr.count('Removing %s://' % self.default_provider), |
| 118 2) |
| 119 self.assertIn('Removing %s#%s...' % (suri(key_uri), g1), stderr) |
| 120 self.assertIn('Removing %s#%s...' % (suri(key_uri), g2), stderr) |
| 121 all_stderr_lines = set() |
| 122 _Check1(all_stderr_lines) |
| 123 self.AssertNObjectsInBucket(bucket_uri, 0, versioned=True) |
| 124 |
| 125 def test_all_versions_no_current(self): |
| 126 """Test that 'rm -a' for an object without a current version works.""" |
| 127 bucket_uri = self.CreateVersionedBucket() |
| 128 key_uri = bucket_uri.clone_replace_name('foo') |
| 129 key_uri.set_contents_from_string('bar') |
| 130 g1 = urigen(key_uri) |
| 131 key_uri.set_contents_from_string('baz') |
| 132 g2 = urigen(key_uri) |
| 133 self._RunRemoveCommandAndCheck( |
| 134 ['-m', 'rm', '-a', suri(key_uri)], |
| 135 objects_to_remove=['%s#%s' % (suri(key_uri), g1), |
| 136 '%s#%s' % (suri(key_uri), g2)]) |
| 137 self.AssertNObjectsInBucket(bucket_uri, 0, versioned=True) |
| 138 |
| 139 def test_fails_for_missing_obj(self): |
| 140 bucket_uri = self.CreateVersionedBucket() |
| 141 stderr = self.RunGsUtil(['rm', '-a', '%s' % suri(bucket_uri, 'foo')], |
| 142 return_stderr=True, expected_status=1) |
| 143 self.assertIn('No URLs matched', stderr) |
| 144 |
| 145 def test_remove_all_versions_recursive_on_bucket(self): |
| 146 """Test that 'rm -r' works on bucket.""" |
| 147 bucket_uri = self.CreateVersionedBucket() |
| 148 k1_uri = bucket_uri.clone_replace_name('foo') |
| 149 k2_uri = bucket_uri.clone_replace_name('foo2') |
| 150 k1_uri.set_contents_from_string('bar') |
| 151 k2_uri.set_contents_from_string('bar2') |
| 152 k1g1 = urigen(k1_uri) |
| 153 k2g1 = urigen(k2_uri) |
| 154 k1_uri.set_contents_from_string('baz') |
| 155 k2_uri.set_contents_from_string('baz2') |
| 156 k1g2 = urigen(k1_uri) |
| 157 k2g2 = urigen(k2_uri) |
| 158 |
| 159 self.AssertNObjectsInBucket(bucket_uri, 4, versioned=True) |
| 160 |
| 161 self._RunRemoveCommandAndCheck( |
| 162 ['rm', '-r', suri(bucket_uri)], |
| 163 objects_to_remove=['%s#%s' % (suri(k1_uri), k1g1), |
| 164 '%s#%s' % (suri(k1_uri), k1g2), |
| 165 '%s#%s' % (suri(k2_uri), k2g1), |
| 166 '%s#%s' % (suri(k2_uri), k2g2)], |
| 167 buckets_to_remove=[suri(bucket_uri)]) |
| 168 |
| 169 # Use @Retry as hedge against bucket listing eventual consistency. |
| 170 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 171 def _Check(): |
| 172 # Bucket should no longer exist. |
| 173 stderr = self.RunGsUtil(['ls', '-a', suri(bucket_uri)], |
| 174 return_stderr=True, expected_status=1) |
| 175 self.assertIn('bucket does not exist', stderr) |
| 176 _Check() |
| 177 |
| 178 def test_remove_all_versions_recursive_on_subdir(self): |
| 179 """Test that 'rm -r' works on subdir.""" |
| 180 bucket_uri = self.CreateVersionedBucket() |
| 181 k1_uri = bucket_uri.clone_replace_name('dir/foo') |
| 182 k2_uri = bucket_uri.clone_replace_name('dir/foo2') |
| 183 k1_uri.set_contents_from_string('bar') |
| 184 k2_uri.set_contents_from_string('bar2') |
| 185 k1g1 = urigen(k1_uri) |
| 186 k2g1 = urigen(k2_uri) |
| 187 k1_uri.set_contents_from_string('baz') |
| 188 k2_uri.set_contents_from_string('baz2') |
| 189 k1g2 = urigen(k1_uri) |
| 190 k2g2 = urigen(k2_uri) |
| 191 |
| 192 self.AssertNObjectsInBucket(bucket_uri, 4, versioned=True) |
| 193 |
| 194 self._RunRemoveCommandAndCheck( |
| 195 ['rm', '-r', '%s' % suri(bucket_uri, 'dir')], |
| 196 objects_to_remove=['%s#%s' % (suri(k1_uri), k1g1), |
| 197 '%s#%s' % (suri(k1_uri), k1g2), |
| 198 '%s#%s' % (suri(k2_uri), k2g1), |
| 199 '%s#%s' % (suri(k2_uri), k2g2)]) |
| 200 self.AssertNObjectsInBucket(bucket_uri, 0, versioned=True) |
| 201 |
| 202 def test_missing_first_force(self): |
| 203 bucket_uri = self.CreateBucket() |
| 204 object_uri = self.CreateObject(bucket_uri=bucket_uri, object_name='present', |
| 205 contents='foo') |
| 206 self.AssertNObjectsInBucket(bucket_uri, 1) |
| 207 self.RunGsUtil(['rm', '%s' % suri(bucket_uri, 'missing'), |
| 208 suri(object_uri)], expected_status=1) |
| 209 stderr = self.RunGsUtil( |
| 210 ['rm', '-f', '%s' % suri(bucket_uri, 'missing'), suri(object_uri)], |
| 211 return_stderr=True, expected_status=1) |
| 212 self.assertEqual(stderr.count('Removing %s://' % self.default_provider), 1) |
| 213 self.RunGsUtil(['stat', suri(object_uri)], expected_status=1) |
| 214 |
| 215 def test_some_missing(self): |
| 216 """Test that 'rm -a' fails when some but not all uris don't exist.""" |
| 217 bucket_uri = self.CreateVersionedBucket() |
| 218 key_uri = bucket_uri.clone_replace_name('foo') |
| 219 key_uri.set_contents_from_string('bar') |
| 220 self.AssertNObjectsInBucket(bucket_uri, 1, versioned=True) |
| 221 stderr = self.RunGsUtil(['rm', '-a', suri(key_uri), |
| 222 '%s' % suri(bucket_uri, 'missing')], |
| 223 return_stderr=True, expected_status=1) |
| 224 self.assertEqual(stderr.count('Removing %s://' % self.default_provider), 1) |
| 225 self.assertIn('No URLs matched', stderr) |
| 226 |
| 227 def test_some_missing_force(self): |
| 228 """Test that 'rm -af' succeeds despite hidden first uri.""" |
| 229 bucket_uri = self.CreateVersionedBucket() |
| 230 key_uri = bucket_uri.clone_replace_name('foo') |
| 231 key_uri.set_contents_from_string('bar') |
| 232 self.AssertNObjectsInBucket(bucket_uri, 1, versioned=True) |
| 233 stderr = self.RunGsUtil( |
| 234 ['rm', '-af', suri(key_uri), '%s' % suri(bucket_uri, 'missing')], |
| 235 return_stderr=True, expected_status=1) |
| 236 self.assertEqual(stderr.count('Removing %s://' % self.default_provider), 1) |
| 237 self.AssertNObjectsInBucket(bucket_uri, 0) |
| 238 |
| 239 def test_folder_objects_deleted(self): |
| 240 """Test for 'rm -r' of a folder with a dir_$folder$ marker.""" |
| 241 bucket_uri = self.CreateVersionedBucket() |
| 242 key_uri = bucket_uri.clone_replace_name('abc/o1') |
| 243 key_uri.set_contents_from_string('foobar') |
| 244 folder_uri = bucket_uri.clone_replace_name('abc_$folder$') |
| 245 folder_uri.set_contents_from_string('') |
| 246 self.AssertNObjectsInBucket(bucket_uri, 2, versioned=True) |
| 247 # This could fail due to eventual listing consistency, so use retry and |
| 248 # expected_status=None to guard against No URLs matched exceptions. |
| 249 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 250 def _RemoveAndCheck(): |
| 251 self.RunGsUtil(['rm', '-r', '%s' % suri(bucket_uri, 'abc')], |
| 252 expected_status=None) |
| 253 self.AssertNObjectsInBucket(bucket_uri, 0, versioned=True) |
| 254 _RemoveAndCheck() |
| 255 # Bucket should not be deleted (Should not get ServiceException). |
| 256 bucket_uri.get_location(validate=False) |
| 257 |
| 258 def test_folder_objects_deleted_with_wildcard(self): |
| 259 """Test for 'rm -r' of a folder with a dir_$folder$ marker.""" |
| 260 bucket_uri = self.CreateVersionedBucket() |
| 261 key_uri = bucket_uri.clone_replace_name('abc/o1') |
| 262 key_uri.set_contents_from_string('foobar') |
| 263 folder_uri = bucket_uri.clone_replace_name('abc_$folder$') |
| 264 folder_uri.set_contents_from_string('') |
| 265 |
| 266 self.AssertNObjectsInBucket(bucket_uri, 2, versioned=True) |
| 267 self._RunRemoveCommandAndCheck( |
| 268 ['rm', '-r', '%s' % suri(bucket_uri, '**')], |
| 269 objects_to_remove=['%s#%s' % (suri(key_uri), urigen(key_uri)), |
| 270 '%s#%s' % (suri(folder_uri), urigen(folder_uri))]) |
| 271 self.AssertNObjectsInBucket(bucket_uri, 0, versioned=True) |
| 272 # Bucket should not be deleted (Should not get ServiceException). |
| 273 bucket_uri.get_location(validate=False) |
| 274 |
| 275 @SkipForS3('Listing/removing S3 DeleteMarkers is not supported') |
| 276 def test_recursive_bucket_rm(self): |
| 277 """Test for 'rm -r' of a bucket.""" |
| 278 bucket_uri = self.CreateBucket() |
| 279 object_uri = self.CreateObject(bucket_uri, contents='foo') |
| 280 self.AssertNObjectsInBucket(bucket_uri, 1) |
| 281 self._RunRemoveCommandAndCheck( |
| 282 ['rm', '-r', suri(bucket_uri)], |
| 283 objects_to_remove=['%s#%s' % (suri(object_uri), urigen(object_uri))], |
| 284 buckets_to_remove=[suri(bucket_uri)]) |
| 285 |
| 286 # Use @Retry as hedge against bucket listing eventual consistency. |
| 287 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 288 def _Check1(): |
| 289 # Bucket should be deleted. |
| 290 stderr = self.RunGsUtil(['ls', '-Lb', suri(bucket_uri)], |
| 291 return_stderr=True, expected_status=1) |
| 292 self.assertIn('bucket does not exist', stderr) |
| 293 _Check1() |
| 294 |
| 295 # Now try same thing, but for a versioned bucket with multiple versions of |
| 296 # an object present. |
| 297 bucket_uri = self.CreateVersionedBucket() |
| 298 self.CreateObject(bucket_uri, 'obj', 'z') |
| 299 self.CreateObject(bucket_uri, 'obj', 'z') |
| 300 final_uri = self.CreateObject(bucket_uri, 'obj', 'z') |
| 301 self.AssertNObjectsInBucket(bucket_uri, 3, versioned=True) |
| 302 self._RunRemoveCommandAndCheck(['rm', suri(bucket_uri, '**')], |
| 303 objects_to_remove=['%s' % final_uri]) |
| 304 |
| 305 stderr = self.RunGsUtil(['rb', suri(bucket_uri)], |
| 306 return_stderr=True, expected_status=1) |
| 307 self.assertIn('Bucket is not empty', stderr) |
| 308 |
| 309 # Now try with rm -r. |
| 310 @Retry(AssertionError, tries=3, timeout_secs=1) |
| 311 def _Check2(): |
| 312 self.RunGsUtil(['rm', '-r', suri(bucket_uri)]) |
| 313 # Bucket should be deleted. |
| 314 stderr = self.RunGsUtil(['ls', '-Lb', suri(bucket_uri)], |
| 315 return_stderr=True, expected_status=1) |
| 316 self.assertIn('bucket does not exist', stderr) |
| 317 _Check2() |
| 318 |
| 319 def test_recursive_bucket_rm_with_wildcarding(self): |
| 320 """Tests removing all objects and buckets matching a bucket wildcard.""" |
| 321 buri_base = 'gsutil-test-%s' % self.GetTestMethodName() |
| 322 buri_base = buri_base[:MAX_BUCKET_LENGTH-20] |
| 323 buri_base = '%s-%s' % (buri_base, self.MakeRandomTestString()) |
| 324 buri1 = self.CreateBucket(bucket_name='%s-tbuck1' % buri_base) |
| 325 buri2 = self.CreateBucket(bucket_name='%s-tbuck2' % buri_base) |
| 326 buri3 = self.CreateBucket(bucket_name='%s-tb3' % buri_base) |
| 327 ouri1 = self.CreateObject(bucket_uri=buri1, object_name='o1', contents='z') |
| 328 ouri2 = self.CreateObject(bucket_uri=buri2, object_name='o2', contents='z') |
| 329 self.CreateObject(bucket_uri=buri3, object_name='o3', contents='z') |
| 330 |
| 331 self.AssertNObjectsInBucket(buri1, 1) |
| 332 self.AssertNObjectsInBucket(buri2, 1) |
| 333 self.AssertNObjectsInBucket(buri3, 1) |
| 334 |
| 335 self._RunRemoveCommandAndCheck( |
| 336 ['rm', '-r', '%s://%s-tbu*' % (self.default_provider, buri_base)], |
| 337 objects_to_remove=['%s#%s' % (suri(ouri1), urigen(ouri1)), |
| 338 '%s#%s' % (suri(ouri2), urigen(ouri2))], |
| 339 buckets_to_remove=[suri(buri1), suri(buri2)]) |
| 340 |
| 341 self.AssertNObjectsInBucket(buri3, 1) |
| 342 |
| 343 def test_rm_quiet(self): |
| 344 """Test that 'rm -q' outputs no progress indications.""" |
| 345 bucket_uri = self.CreateBucket() |
| 346 key_uri = self.CreateObject(bucket_uri=bucket_uri, contents='foo') |
| 347 self.AssertNObjectsInBucket(bucket_uri, 1) |
| 348 self._RunRemoveCommandAndCheck(['-q', 'rm', suri(key_uri)], []) |
| 349 self.AssertNObjectsInBucket(bucket_uri, 0) |
| 350 |
| 351 def test_rm_object_with_slash(self): |
| 352 """Tests removing a bucket that has an object with a slash in it.""" |
| 353 bucket_uri = self.CreateVersionedBucket() |
| 354 ouri1 = self.CreateObject(bucket_uri=bucket_uri, |
| 355 object_name='/dirwithslash/foo', contents='z') |
| 356 ouri2 = self.CreateObject(bucket_uri=bucket_uri, |
| 357 object_name='dirnoslash/foo', contents='z') |
| 358 ouri3 = self.CreateObject(bucket_uri=bucket_uri, |
| 359 object_name='dirnoslash/foo2', contents='z') |
| 360 |
| 361 self.AssertNObjectsInBucket(bucket_uri, 3, versioned=True) |
| 362 |
| 363 self._RunRemoveCommandAndCheck( |
| 364 ['rm', '-r', suri(bucket_uri)], |
| 365 objects_to_remove=['%s#%s' % (suri(ouri1), urigen(ouri1)), |
| 366 '%s#%s' % (suri(ouri2), urigen(ouri2)), |
| 367 '%s#%s' % (suri(ouri3), urigen(ouri3))], |
| 368 buckets_to_remove=[suri(bucket_uri)]) |
| 369 |
| 370 def test_slasher_horror_film(self): |
| 371 """Tests removing a bucket with objects that are filled with slashes.""" |
| 372 bucket_uri = self.CreateVersionedBucket() |
| 373 ouri1 = self.CreateObject(bucket_uri=bucket_uri, |
| 374 object_name='h/e/l//lo', |
| 375 contents='Halloween') |
| 376 ouri2 = self.CreateObject(bucket_uri=bucket_uri, |
| 377 object_name='/h/e/l/l/o', |
| 378 contents='A Nightmare on Elm Street') |
| 379 ouri3 = self.CreateObject(bucket_uri=bucket_uri, |
| 380 object_name='//h//e/l//l/o', |
| 381 contents='Friday the 13th') |
| 382 ouri4 = self.CreateObject(bucket_uri=bucket_uri, |
| 383 object_name='//h//e//l//l//o', |
| 384 contents='I Know What You Did Last Summer') |
| 385 ouri5 = self.CreateObject(bucket_uri=bucket_uri, |
| 386 object_name='/', |
| 387 contents='Scream') |
| 388 ouri6 = self.CreateObject(bucket_uri=bucket_uri, |
| 389 object_name='//', |
| 390 contents='Child\'s Play') |
| 391 ouri7 = self.CreateObject(bucket_uri=bucket_uri, |
| 392 object_name='///', |
| 393 contents='The Prowler') |
| 394 ouri8 = self.CreateObject(bucket_uri=bucket_uri, |
| 395 object_name='////', |
| 396 contents='Black Christmas') |
| 397 ouri9 = self.CreateObject( |
| 398 bucket_uri=bucket_uri, |
| 399 object_name='everything/is/better/with/slashes///////', |
| 400 contents='Maniac') |
| 401 |
| 402 self.AssertNObjectsInBucket(bucket_uri, 9, versioned=True) |
| 403 |
| 404 # We add a slash to URIs with a trailing slash, |
| 405 # because ObjectToURI (suri) removes one trailing slash. |
| 406 objects_to_remove = [ |
| 407 '%s#%s' % (suri(ouri1), urigen(ouri1)), |
| 408 '%s#%s' % (suri(ouri2), urigen(ouri2)), |
| 409 '%s#%s' % (suri(ouri3), urigen(ouri3)), |
| 410 '%s#%s' % (suri(ouri4), urigen(ouri4)), |
| 411 '%s#%s' % (suri(ouri5) + '/', urigen(ouri5)), |
| 412 '%s#%s' % (suri(ouri6) + '/', urigen(ouri6)), |
| 413 '%s#%s' % (suri(ouri7) + '/', urigen(ouri7)), |
| 414 '%s#%s' % (suri(ouri8) + '/', urigen(ouri8)), |
| 415 '%s#%s' % (suri(ouri9) + '/', urigen(ouri9))] |
| 416 |
| 417 self._RunRemoveCommandAndCheck(['-m', 'rm', '-r', suri(bucket_uri)], |
| 418 objects_to_remove=objects_to_remove, |
| 419 buckets_to_remove=[suri(bucket_uri)]) |
| 420 |
| 421 @SkipForS3('GCS versioning headers not supported by S3') |
| 422 def test_rm_failing_precondition(self): |
| 423 """Test for '-h x-goog-if-generation-match:value rm' of an object.""" |
| 424 bucket_uri = self.CreateBucket() |
| 425 object_uri = self.CreateObject(bucket_uri, contents='foo') |
| 426 stderr = self.RunGsUtil(['-h', 'x-goog-if-generation-match:12345', 'rm', |
| 427 suri(object_uri)], return_stderr=True, |
| 428 expected_status=1) |
| 429 self.assertRegexpMatches( |
| 430 stderr, r'PreconditionException: 412 Precondition\s*Failed') |
| 431 |
| 432 def test_stdin_args(self): |
| 433 """Tests rm with the -I option.""" |
| 434 buri1 = self.CreateVersionedBucket() |
| 435 ouri1 = self.CreateObject(bucket_uri=buri1, |
| 436 object_name='foo', |
| 437 contents='foocontents') |
| 438 ouri2 = self.CreateObject(bucket_uri=buri1, |
| 439 object_name='bar', |
| 440 contents='barcontents') |
| 441 ouri3 = self.CreateObject(bucket_uri=buri1, |
| 442 object_name='baz', |
| 443 contents='bazcontents') |
| 444 buri2 = self.CreateVersionedBucket() |
| 445 ouri4 = self.CreateObject(bucket_uri=buri2, |
| 446 object_name='moo', |
| 447 contents='moocontents') |
| 448 self.AssertNObjectsInBucket(buri1, 3, versioned=True) |
| 449 self.AssertNObjectsInBucket(buri2, 1, versioned=True) |
| 450 |
| 451 objects_to_remove = ['%s#%s' % (suri(ouri1), urigen(ouri1)), |
| 452 '%s#%s' % (suri(ouri3), urigen(ouri3)), |
| 453 '%s#%s' % (suri(ouri4), urigen(ouri4))] |
| 454 stdin = '\n'.join(objects_to_remove) |
| 455 self._RunRemoveCommandAndCheck(['rm', '-I'], |
| 456 objects_to_remove=objects_to_remove, |
| 457 stdin=stdin) |
| 458 self.AssertNObjectsInBucket(buri1, 1, versioned=True) |
| 459 self.AssertNObjectsInBucket(buri2, 0, versioned=True) |
OLD | NEW |