25
25
import requests
26
26
27
27
import storage_add_bucket_label
28
- import storage_async_upload
29
28
import storage_async_download
29
+ import storage_async_upload
30
30
import storage_batch_request
31
31
import storage_bucket_delete_default_kms_key
32
32
import storage_change_default_storage_class
44
44
import storage_delete_file
45
45
import storage_delete_file_archived_generation
46
46
import storage_disable_bucket_lifecycle_management
47
+ import storage_disable_soft_delete
47
48
import storage_disable_versioning
48
49
import storage_download_byte_range
49
50
import storage_download_file
59
60
import storage_get_autoclass
60
61
import storage_get_bucket_labels
61
62
import storage_get_bucket_metadata
62
- import storage_get_soft_deleted_bucket
63
63
import storage_get_metadata
64
64
import storage_get_service_account
65
+ import storage_get_soft_delete_policy
66
+ import storage_get_soft_deleted_bucket
65
67
import storage_list_buckets
66
- import storage_list_soft_deleted_buckets
67
- import storage_restore_soft_deleted_bucket
68
68
import storage_list_file_archived_generations
69
69
import storage_list_files
70
70
import storage_list_files_with_prefix
71
+ import storage_list_soft_deleted_buckets
72
+ import storage_list_soft_deleted_object_versions
73
+ import storage_list_soft_deleted_objects
71
74
import storage_make_public
72
75
import storage_move_file
73
76
import storage_object_get_kms_key
74
77
import storage_remove_bucket_label
75
78
import storage_remove_cors_configuration
76
79
import storage_rename_file
80
+ import storage_restore_object
81
+ import storage_restore_soft_deleted_bucket
77
82
import storage_set_autoclass
78
83
import storage_set_bucket_default_kms_key
79
84
import storage_set_client_endpoint
80
- import storage_set_object_retention_policy
81
85
import storage_set_metadata
86
+ import storage_set_object_retention_policy
87
+ import storage_set_soft_delete_policy
82
88
import storage_trace_quickstart
83
89
import storage_transfer_manager_download_bucket
84
90
import storage_transfer_manager_download_chunks_concurrently
@@ -147,6 +153,21 @@ def test_soft_deleted_bucket():
147
153
yield bucket
148
154
149
155
156
+ @pytest .fixture (scope = "function" )
157
+ def test_soft_delete_enabled_bucket ():
158
+ """Yields a bucket with soft-delete enabled that is deleted after the test completes."""
159
+ bucket = None
160
+ while bucket is None or bucket .exists ():
161
+ bucket_name = f"storage-snippets-test-{ uuid .uuid4 ()} "
162
+ bucket = storage .Client ().bucket (bucket_name )
163
+ # Soft-delete retention for 7 days (minimum allowed by API)
164
+ bucket .soft_delete_policy .retention_duration_seconds = 7 * 24 * 60 * 60
165
+ # Soft-delete requires a region
166
+ bucket .create (location = "US-CENTRAL1" )
167
+ yield bucket
168
+ bucket .delete (force = True )
169
+
170
+
150
171
@pytest .fixture (scope = "function" )
151
172
def test_public_bucket ():
152
173
# The new projects don't allow to make a bucket available to public, so
@@ -230,13 +251,17 @@ def test_bucket_metadata(test_bucket, capsys):
230
251
231
252
232
253
def test_get_soft_deleted_bucket (test_soft_deleted_bucket , capsys ):
233
- storage_get_soft_deleted_bucket .get_soft_deleted_bucket (test_soft_deleted_bucket .name , test_soft_deleted_bucket .generation )
254
+ storage_get_soft_deleted_bucket .get_soft_deleted_bucket (
255
+ test_soft_deleted_bucket .name , test_soft_deleted_bucket .generation
256
+ )
234
257
out , _ = capsys .readouterr ()
235
258
assert test_soft_deleted_bucket .name in out
236
259
237
260
238
261
def test_restore_soft_deleted_bucket (test_soft_deleted_bucket , capsys ):
239
- storage_restore_soft_deleted_bucket .restore_bucket (test_soft_deleted_bucket .name , test_soft_deleted_bucket .generation )
262
+ storage_restore_soft_deleted_bucket .restore_bucket (
263
+ test_soft_deleted_bucket .name , test_soft_deleted_bucket .generation
264
+ )
240
265
out , _ = capsys .readouterr ()
241
266
assert test_soft_deleted_bucket .name in out
242
267
@@ -309,7 +334,9 @@ def test_async_download(test_bucket, capsys):
309
334
blob = test_bucket .blob (source )
310
335
blob .upload_from_string (source )
311
336
312
- asyncio .run (storage_async_download .async_download_blobs (test_bucket .name , * source_files ))
337
+ asyncio .run (
338
+ storage_async_download .async_download_blobs (test_bucket .name , * source_files )
339
+ )
313
340
out , _ = capsys .readouterr ()
314
341
for x in range (object_count ):
315
342
assert f"Downloaded storage object async_sample_blob_{ x } " in out
@@ -877,7 +904,10 @@ def test_object_retention_policy(test_bucket_create, capsys):
877
904
test_bucket_create .name
878
905
)
879
906
out , _ = capsys .readouterr ()
880
- assert f"Created bucket { test_bucket_create .name } with object retention enabled setting" in out
907
+ assert (
908
+ f"Created bucket { test_bucket_create .name } with object retention enabled setting"
909
+ in out
910
+ )
881
911
882
912
blob_name = "test_object_retention"
883
913
storage_set_object_retention_policy .set_object_retention_policy (
@@ -898,7 +928,10 @@ def test_create_bucket_hierarchical_namespace(test_bucket_create, capsys):
898
928
test_bucket_create .name
899
929
)
900
930
out , _ = capsys .readouterr ()
901
- assert f"Created bucket { test_bucket_create .name } with hierarchical namespace enabled" in out
931
+ assert (
932
+ f"Created bucket { test_bucket_create .name } with hierarchical namespace enabled"
933
+ in out
934
+ )
902
935
903
936
904
937
def test_storage_trace_quickstart (test_bucket , capsys ):
@@ -911,3 +944,96 @@ def test_storage_trace_quickstart(test_bucket, capsys):
911
944
assert (
912
945
f"Downloaded storage object { blob_name } from bucket { test_bucket .name } " in out
913
946
)
947
+
948
+
949
+ def test_storage_disable_soft_delete (test_soft_delete_enabled_bucket , capsys ):
950
+ bucket_name = test_soft_delete_enabled_bucket .name
951
+ storage_disable_soft_delete .disable_soft_delete (bucket_name )
952
+ out , _ = capsys .readouterr ()
953
+ assert f"Soft-delete policy is disabled for bucket { bucket_name } " in out
954
+
955
+
956
+ def test_storage_get_soft_delete_policy (test_soft_delete_enabled_bucket , capsys ):
957
+ bucket_name = test_soft_delete_enabled_bucket .name
958
+ storage_get_soft_delete_policy .get_soft_delete_policy (bucket_name )
959
+ out , _ = capsys .readouterr ()
960
+ assert f"Soft-delete policy for { bucket_name } " in out
961
+ assert "Object soft-delete policy is enabled" in out
962
+ assert "Object retention duration: " in out
963
+ assert "Policy effective time: " in out
964
+
965
+ # Disable the soft-delete policy
966
+ test_soft_delete_enabled_bucket .soft_delete_policy .retention_duration_seconds = 0
967
+ test_soft_delete_enabled_bucket .patch ()
968
+ storage_get_soft_delete_policy .get_soft_delete_policy (bucket_name )
969
+ out , _ = capsys .readouterr ()
970
+ assert f"Soft-delete policy for { bucket_name } " in out
971
+ assert "Object soft-delete policy is disabled" in out
972
+
973
+
974
+ def test_storage_set_soft_delete_policy (test_soft_delete_enabled_bucket , capsys ):
975
+ bucket_name = test_soft_delete_enabled_bucket .name
976
+ retention_duration_seconds = 10 * 24 * 60 * 60 # 10 days
977
+ storage_set_soft_delete_policy .set_soft_delete_policy (
978
+ bucket_name , retention_duration_seconds
979
+ )
980
+ out , _ = capsys .readouterr ()
981
+ assert (
982
+ f"Soft delete policy for bucket { bucket_name } was set to { retention_duration_seconds } seconds retention period"
983
+ in out
984
+ )
985
+
986
+
987
+ def test_storage_list_soft_deleted_objects (test_soft_delete_enabled_bucket , capsys ):
988
+ bucket_name = test_soft_delete_enabled_bucket .name
989
+ blob_name = f"test_object_{ uuid .uuid4 ().hex } .txt"
990
+ blob_content = "This object will be soft-deleted for listing."
991
+ blob = test_soft_delete_enabled_bucket .blob (blob_name )
992
+ blob .upload_from_string (blob_content )
993
+ blob_generation = blob .generation
994
+
995
+ blob .delete () # Soft-delete the object
996
+ storage_list_soft_deleted_objects .list_soft_deleted_objects (bucket_name )
997
+ out , _ = capsys .readouterr ()
998
+ assert f"Name: { blob_name } , Generation: { blob_generation } " in out
999
+
1000
+
1001
+ def test_storage_list_soft_deleted_object_versions (
1002
+ test_soft_delete_enabled_bucket , capsys
1003
+ ):
1004
+ bucket_name = test_soft_delete_enabled_bucket .name
1005
+ blob_name = f"test_object_{ uuid .uuid4 ().hex } .txt"
1006
+ blob_content = "This object will be soft-deleted for version listing."
1007
+ blob = test_soft_delete_enabled_bucket .blob (blob_name )
1008
+ blob .upload_from_string (blob_content )
1009
+ blob_generation = blob .generation
1010
+
1011
+ blob .delete () # Soft-delete the object
1012
+ storage_list_soft_deleted_object_versions .list_soft_deleted_object_versions (
1013
+ bucket_name , blob_name
1014
+ )
1015
+ out , _ = capsys .readouterr ()
1016
+ assert f"Version ID: { blob_generation } " in out
1017
+
1018
+
1019
+ def test_storage_restore_soft_deleted_object (test_soft_delete_enabled_bucket , capsys ):
1020
+ bucket_name = test_soft_delete_enabled_bucket .name
1021
+ blob_name = f"test-restore-sd-obj-{ uuid .uuid4 ().hex } .txt"
1022
+ blob_content = "This object will be soft-deleted and restored."
1023
+ blob = test_soft_delete_enabled_bucket .blob (blob_name )
1024
+ blob .upload_from_string (blob_content )
1025
+ blob_generation = blob .generation
1026
+
1027
+ blob .delete () # Soft-delete the object
1028
+ storage_restore_object .restore_soft_deleted_object (
1029
+ bucket_name , blob_name , blob_generation
1030
+ )
1031
+ out , _ = capsys .readouterr ()
1032
+ assert (
1033
+ f"Soft-deleted object { blob_name } is restored in the bucket { bucket_name } "
1034
+ in out
1035
+ )
1036
+
1037
+ # Verify the restoration
1038
+ blob = test_soft_delete_enabled_bucket .get_blob (blob_name )
1039
+ assert blob is not None
0 commit comments