@@ -255,7 +255,7 @@ async def test_delete_user_bucket(
255255 f"/storage/user-bucket{ '/' if trailing_slash else '' } " ,
256256 headers = {"Authorization" : f"bearer { TEST_USER_TOKEN } " },
257257 )
258- assert res .status_code == 204 , res .text
258+ assert res .status_code == 202 , res .text
259259
260260 # Verify the bucket is deleted
261261 with pytest .raises (ClientError ) as e :
@@ -307,7 +307,7 @@ async def test_delete_user_bucket_with_files(
307307 res = await client .delete (
308308 "/storage/user-bucket" , headers = {"Authorization" : f"bearer { TEST_USER_TOKEN } " }
309309 )
310- assert res .status_code == 204 , res .text
310+ assert res .status_code == 202 , res .text
311311
312312 # Verify the bucket is deleted
313313 with pytest .raises (ClientError ) as e :
@@ -324,7 +324,7 @@ async def test_delete_user_bucket_no_token(client, mock_aws_services):
324324 """
325325 mock_delete_bucket = MagicMock ()
326326 # Delete the bucket
327- with patch ("gen3workflow.aws_utils.delete_user_bucket " , mock_delete_bucket ):
327+ with patch ("gen3workflow.aws_utils.cleanup_user_bucket " , mock_delete_bucket ):
328328 res = await client .delete ("/storage/user-bucket" )
329329 assert res .status_code == 401 , res .text
330330 assert res .json () == {"detail" : "Must provide an access token" }
@@ -346,11 +346,55 @@ async def test_delete_user_bucket_unauthorized(
346346 """
347347 mock_delete_bucket = MagicMock ()
348348 # Delete the bucket
349- with patch ("gen3workflow.aws_utils.delete_user_bucket " , mock_delete_bucket ):
349+ with patch ("gen3workflow.aws_utils.cleanup_user_bucket " , mock_delete_bucket ):
350350 res = await client .delete (
351351 "/storage/user-bucket" ,
352352 headers = {"Authorization" : f"bearer { TEST_USER_TOKEN } " },
353353 )
354354 assert res .status_code == 403 , res .text
355355 assert res .json () == {"detail" : "Permission denied" }
356356 mock_delete_bucket .assert_not_called ()
357+
358+
359+ @pytest .mark .asyncio
360+ async def test_delete_user_bucket_objects_with_existing_files (
361+ client , access_token_patcher , mock_aws_services
362+ ):
363+ """
364+ Attempt to delete all the objects in a bucket that is not empty.
365+ Endpoint must be able to delete all the files but should not delete the bucket.
366+ """
367+
368+ # Create the bucket if it doesn't exist
369+ res = await client .get (
370+ "/storage/info" , headers = {"Authorization" : f"bearer { TEST_USER_TOKEN } " }
371+ )
372+ bucket_name = res .json ()["bucket" ]
373+
374+ # Remove the bucket policy enforcing KMS encryption
375+ # Moto has limitations that prevent adding objects to a bucket with KMS encryption enabled.
376+ # More details: https://github.com/uc-cdis/gen3-workflow/blob/554fc3eb4c1d333f9ef81c1a5f8e75a6b208cdeb/tests/test_misc.py#L161-L171
377+ aws_utils .s3_client .delete_bucket_policy (Bucket = bucket_name )
378+
379+ object_count = 10
380+ for i in range (object_count ):
381+ aws_utils .s3_client .put_object (
382+ Bucket = bucket_name , Key = f"file_{ i } " , Body = b"Dummy file contents"
383+ )
384+
385+ # Delete all the bucket objects
386+ res = await client .delete (
387+ "/storage/user-bucket/objects" ,
388+ headers = {"Authorization" : f"bearer { TEST_USER_TOKEN } " },
389+ )
390+ assert res .status_code == 204 , res .text
391+
392+ # Verify the bucket still exists
393+ bucket_exists = aws_utils .s3_client .head_bucket (Bucket = bucket_name )
394+ assert bucket_exists , f"Bucket '{ bucket_name } is expected to exist but not found"
395+
396+ # Verify all the objects in the bucket are deleted
397+ object_list = aws_utils .get_all_bucket_objects (bucket_name )
398+ assert (
399+ len (object_list ) == 0
400+ ), f"Expected bucket to have no objects, but found { len (object_list )} .\n { object_list = } "
0 commit comments