@@ -1947,6 +1947,116 @@ public void onFailure(Exception e) {
1947
1947
assertEquals (simulatedFailure , exceptionRef .get ().getCause ());
1948
1948
}
1949
1949
1950
+ public void testDeleteWithInterruptedException () throws Exception {
1951
+ final String bucketName = randomAlphaOfLengthBetween (1 , 10 );
1952
+ final BlobPath blobPath = new BlobPath ();
1953
+ final S3BlobStore blobStore = mock (S3BlobStore .class );
1954
+ when (blobStore .bucket ()).thenReturn (bucketName );
1955
+ when (blobStore .getStatsMetricPublisher ()).thenReturn (new StatsMetricPublisher ());
1956
+
1957
+ final S3AsyncClient s3AsyncClient = mock (S3AsyncClient .class );
1958
+ final AmazonAsyncS3Reference asyncClientReference = mock (AmazonAsyncS3Reference .class );
1959
+ when (blobStore .asyncClientReference ()).thenReturn (asyncClientReference );
1960
+ when (asyncClientReference .get ()).thenReturn (AmazonAsyncS3WithCredentials .create (s3AsyncClient , s3AsyncClient , s3AsyncClient , null ));
1961
+
1962
+ // Mock the list operation to block indefinitely
1963
+ final ListObjectsV2Publisher listPublisher = mock (ListObjectsV2Publisher .class );
1964
+ doAnswer (invocation -> {
1965
+ Thread .currentThread ().interrupt ();
1966
+ return null ;
1967
+ }).when (listPublisher ).subscribe (ArgumentMatchers .<Subscriber <ListObjectsV2Response >>any ());
1968
+
1969
+ when (s3AsyncClient .listObjectsV2Paginator (any (ListObjectsV2Request .class ))).thenReturn (listPublisher );
1970
+
1971
+ final S3BlobContainer blobContainer = new S3BlobContainer (blobPath , blobStore );
1972
+
1973
+ IllegalStateException e = expectThrows (IllegalStateException .class , blobContainer ::delete );
1974
+ assertEquals ("Future got interrupted" , e .getMessage ());
1975
+ assertTrue (Thread .interrupted ()); // Clear interrupted state
1976
+ }
1977
+
1978
+ public void testDeleteWithExecutionException () throws Exception {
1979
+ final String bucketName = randomAlphaOfLengthBetween (1 , 10 );
1980
+ final BlobPath blobPath = new BlobPath ();
1981
+ final S3BlobStore blobStore = mock (S3BlobStore .class );
1982
+ when (blobStore .bucket ()).thenReturn (bucketName );
1983
+ when (blobStore .getStatsMetricPublisher ()).thenReturn (new StatsMetricPublisher ());
1984
+
1985
+ final S3AsyncClient s3AsyncClient = mock (S3AsyncClient .class );
1986
+ final AmazonAsyncS3Reference asyncClientReference = mock (AmazonAsyncS3Reference .class );
1987
+ when (blobStore .asyncClientReference ()).thenReturn (asyncClientReference );
1988
+ when (asyncClientReference .get ()).thenReturn (AmazonAsyncS3WithCredentials .create (s3AsyncClient , s3AsyncClient , s3AsyncClient , null ));
1989
+
1990
+ RuntimeException simulatedError = new RuntimeException ("Simulated error" );
1991
+ final ListObjectsV2Publisher listPublisher = mock (ListObjectsV2Publisher .class );
1992
+ doAnswer (invocation -> {
1993
+ Subscriber <? super ListObjectsV2Response > subscriber = invocation .getArgument (0 );
1994
+ subscriber .onError (simulatedError );
1995
+ return null ;
1996
+ }).when (listPublisher ).subscribe (ArgumentMatchers .<Subscriber <ListObjectsV2Response >>any ());
1997
+
1998
+ when (s3AsyncClient .listObjectsV2Paginator (any (ListObjectsV2Request .class ))).thenReturn (listPublisher );
1999
+
2000
+ final S3BlobContainer blobContainer = new S3BlobContainer (blobPath , blobStore );
2001
+
2002
+ IOException e = expectThrows (IOException .class , blobContainer ::delete );
2003
+ assertEquals ("Failed to list objects for deletion" , e .getMessage ());
2004
+ assertEquals (simulatedError , e .getCause ());
2005
+ }
2006
+
2007
+ public void testDeleteBlobsIgnoringIfNotExistsWithInterruptedException () throws Exception {
2008
+ final String bucketName = randomAlphaOfLengthBetween (1 , 10 );
2009
+ final BlobPath blobPath = new BlobPath ();
2010
+ final S3BlobStore blobStore = mock (S3BlobStore .class );
2011
+ when (blobStore .bucket ()).thenReturn (bucketName );
2012
+ when (blobStore .getStatsMetricPublisher ()).thenReturn (new StatsMetricPublisher ());
2013
+ when (blobStore .getBulkDeletesSize ()).thenReturn (5 );
2014
+
2015
+ final S3AsyncClient s3AsyncClient = mock (S3AsyncClient .class );
2016
+ final AmazonAsyncS3Reference asyncClientReference = mock (AmazonAsyncS3Reference .class );
2017
+ when (blobStore .asyncClientReference ()).thenReturn (asyncClientReference );
2018
+ when (asyncClientReference .get ()).thenReturn (AmazonAsyncS3WithCredentials .create (s3AsyncClient , s3AsyncClient , s3AsyncClient , null ));
2019
+
2020
+ // Mock deleteObjects to block indefinitely
2021
+ when (s3AsyncClient .deleteObjects (any (DeleteObjectsRequest .class ))).thenAnswer (invocation -> {
2022
+ Thread .currentThread ().interrupt ();
2023
+ return null ;
2024
+ });
2025
+
2026
+ final S3BlobContainer blobContainer = new S3BlobContainer (blobPath , blobStore );
2027
+ List <String > blobNames = Arrays .asList ("test1" , "test2" );
2028
+
2029
+ IllegalStateException e = expectThrows (IllegalStateException .class , () -> blobContainer .deleteBlobsIgnoringIfNotExists (blobNames ));
2030
+ assertEquals ("Future got interrupted" , e .getMessage ());
2031
+ assertTrue (Thread .interrupted ()); // Clear interrupted state
2032
+ }
2033
+
2034
+ public void testDeleteBlobsIgnoringIfNotExistsWithExecutionException () throws Exception {
2035
+ final String bucketName = randomAlphaOfLengthBetween (1 , 10 );
2036
+ final BlobPath blobPath = new BlobPath ();
2037
+ final S3BlobStore blobStore = mock (S3BlobStore .class );
2038
+ when (blobStore .bucket ()).thenReturn (bucketName );
2039
+ when (blobStore .getStatsMetricPublisher ()).thenReturn (new StatsMetricPublisher ());
2040
+ when (blobStore .getBulkDeletesSize ()).thenReturn (5 );
2041
+
2042
+ final S3AsyncClient s3AsyncClient = mock (S3AsyncClient .class );
2043
+ final AmazonAsyncS3Reference asyncClientReference = mock (AmazonAsyncS3Reference .class );
2044
+ when (blobStore .asyncClientReference ()).thenReturn (asyncClientReference );
2045
+ when (asyncClientReference .get ()).thenReturn (AmazonAsyncS3WithCredentials .create (s3AsyncClient , s3AsyncClient , s3AsyncClient , null ));
2046
+
2047
+ RuntimeException simulatedError = new RuntimeException ("Simulated delete error" );
2048
+ CompletableFuture <DeleteObjectsResponse > failedFuture = new CompletableFuture <>();
2049
+ failedFuture .completeExceptionally (simulatedError );
2050
+ when (s3AsyncClient .deleteObjects (any (DeleteObjectsRequest .class ))).thenReturn (failedFuture );
2051
+
2052
+ final S3BlobContainer blobContainer = new S3BlobContainer (blobPath , blobStore );
2053
+ List <String > blobNames = Arrays .asList ("test1" , "test2" );
2054
+
2055
+ IOException e = expectThrows (IOException .class , () -> blobContainer .deleteBlobsIgnoringIfNotExists (blobNames ));
2056
+ assertEquals ("Failed to delete blobs " + blobNames , e .getMessage ());
2057
+ assertEquals (simulatedError , e .getCause ().getCause ());
2058
+ }
2059
+
1950
2060
private void mockObjectResponse (S3AsyncClient s3AsyncClient , String bucketName , String blobName , int objectSize ) {
1951
2061
1952
2062
final InputStream inputStream = new ByteArrayInputStream (randomByteArrayOfLength (objectSize ));
0 commit comments