diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py index bc3f1e026..de3b2502e 100644 --- a/google/cloud/storage/bucket.py +++ b/google/cloud/storage/bucket.py @@ -1539,6 +1539,7 @@ def delete( client=client, timeout=timeout, retry=retry, + versions=True, ) ) if len(blobs) > self._MAX_OBJECTS_FOR_ITERATION: @@ -1557,6 +1558,7 @@ def delete( client=client, timeout=timeout, retry=retry, + preserve_generation=True, ) # We intentionally pass `_target_object=None` since a DELETE diff --git a/tests/system/test_bucket.py b/tests/system/test_bucket.py index e825c72a6..19b21bac2 100644 --- a/tests/system/test_bucket.py +++ b/tests/system/test_bucket.py @@ -1069,6 +1069,48 @@ def test_new_bucket_with_autoclass( assert bucket.autoclass_toggle_time != previous_toggle_time +def test_bucket_delete_force(storage_client): + bucket_name = _helpers.unique_name("version-disabled") + bucket_obj = storage_client.bucket(bucket_name) + bucket = storage_client.create_bucket(bucket_obj) + + BLOB_NAME = "my_object" + blob = bucket.blob(BLOB_NAME) + blob.upload_from_string("abcd") + blob.upload_from_string("efgh") + + blobs = bucket.list_blobs(versions=True) + counter = 0 + for blob in blobs: + counter += 1 + assert blob.name == BLOB_NAME + assert counter == 1 + + bucket.delete(force=True) # Will fail with 409 if blobs aren't deleted + + +def test_bucket_delete_force_works_with_versions(storage_client): + bucket_name = _helpers.unique_name("version-enabled") + bucket_obj = storage_client.bucket(bucket_name) + bucket_obj.versioning_enabled = True + bucket = storage_client.create_bucket(bucket_obj) + assert bucket.versioning_enabled + + BLOB_NAME = "my_versioned_object" + blob = bucket.blob(BLOB_NAME) + blob.upload_from_string("abcd") + blob.upload_from_string("efgh") + + blobs = bucket.list_blobs(versions=True) + counter = 0 + for blob in blobs: + counter += 1 + assert blob.name == BLOB_NAME + assert counter == 2 + + bucket.delete(force=True) # Will fail with 409 if versions aren't deleted + + def test_config_autoclass_w_existing_bucket( storage_client, buckets_to_delete, diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py index 8e07ed96d..8db6a2e62 100644 --- a/tests/unit/test_bucket.py +++ b/tests/unit/test_bucket.py @@ -1419,6 +1419,7 @@ def test_delete_hit_w_force_w_user_project_w_explicit_timeout_retry(self): client=client, timeout=timeout, retry=retry, + versions=True, ) bucket.delete_blobs.assert_called_once_with( @@ -1427,6 +1428,7 @@ def test_delete_hit_w_force_w_user_project_w_explicit_timeout_retry(self): client=client, timeout=timeout, retry=retry, + preserve_generation=True, ) expected_query_params = {"userProject": user_project} @@ -1456,6 +1458,7 @@ def test_delete_hit_w_force_delete_blobs(self): client=client, timeout=self._get_default_timeout(), retry=DEFAULT_RETRY, + versions=True, ) bucket.delete_blobs.assert_called_once_with( @@ -1464,6 +1467,7 @@ def test_delete_hit_w_force_delete_blobs(self): client=client, timeout=self._get_default_timeout(), retry=DEFAULT_RETRY, + preserve_generation=True, ) expected_query_params = {} @@ -1483,8 +1487,10 @@ def test_delete_w_force_w_user_project_w_miss_on_blob(self): client = mock.Mock(spec=["_delete_resource"]) client._delete_resource.return_value = None bucket = self._make_one(client=client, name=name) - blob = mock.Mock(spec=["name"]) + blob = mock.Mock(spec=["name", "generation"]) blob.name = blob_name + GEN = 1234 + blob.generation = GEN blobs = [blob] bucket.list_blobs = mock.Mock(return_value=iter(blobs)) bucket.delete_blob = mock.Mock(side_effect=NotFound("testing")) @@ -1496,7 +1502,7 @@ def test_delete_w_force_w_user_project_w_miss_on_blob(self): bucket.delete_blob.assert_called_once_with( blob_name, client=client, - generation=None, + generation=GEN, if_generation_match=None, if_generation_not_match=None, if_metageneration_match=None,