diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java index 73bd66520182..024aa04eba1b 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/testing/RemoteGcsHelper.java @@ -65,7 +65,10 @@ public StorageOptions options() { /** * Deletes a bucket, even if non-empty. Objects in the bucket are listed and deleted until bucket - * deletion succeeds or {@code timeout} expires. + * deletion succeeds or {@code timeout} expires. To allow for the timeout, this method uses a + * separate thread to send the delete requests. Use + * {@link #forceDelete(Storage storage, String bucket)} if spawning an additional thread is + * undesirable, such as in the App Engine production runtime. * * @param storage the storage service to be used to issue requests * @param bucket the bucket to be deleted @@ -88,6 +91,17 @@ public static Boolean forceDelete(Storage storage, String bucket, long timeout, } } + /** + * Deletes a bucket, even if non-empty. This method blocks until the deletion completes or fails. + * + * @param storage the storage service to be used to issue requests + * @param bucket the bucket to be deleted + * @throws StorageException if an exception is encountered during bucket deletion + */ + public static void forceDelete(Storage storage, String bucket) { + new DeleteBucketTask(storage, bucket).call(); + } + /** * Returns a bucket name generated using a random UUID. */ @@ -157,7 +171,7 @@ public DeleteBucketTask(Storage storage, String bucket) { } @Override - public Boolean call() throws Exception { + public Boolean call() { while (true) { for (BlobInfo info : storage.list(bucket).values()) { storage.delete(bucket, info.name()); @@ -167,7 +181,12 @@ public Boolean call() throws Exception { return true; } catch (StorageException e) { if (e.code() == 409) { - Thread.sleep(500); + try { + Thread.sleep(500); + } catch (InterruptedException interruptedException) { + Thread.currentThread().interrupt(); + throw e; + } } else { throw e; } diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteGcsHelperTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteGcsHelperTest.java index 6b67a9576dc6..05b7f5f6fd8c 100644 --- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteGcsHelperTest.java +++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteGcsHelperTest.java @@ -140,6 +140,36 @@ public void testForceDeleteFail() throws InterruptedException, ExecutionExceptio } } + @Test + public void testForceDeleteNoTimeout() { + Storage storageMock = EasyMock.createMock(Storage.class); + EasyMock.expect(storageMock.list(BUCKET_NAME)).andReturn(BLOB_PAGE); + for (BlobInfo info : BLOB_LIST) { + EasyMock.expect(storageMock.delete(BUCKET_NAME, info.name())).andReturn(true); + } + EasyMock.expect(storageMock.delete(BUCKET_NAME)).andReturn(true); + EasyMock.replay(storageMock); + RemoteGcsHelper.forceDelete(storageMock, BUCKET_NAME); + EasyMock.verify(storageMock); + } + + @Test + public void testForceDeleteNoTimeoutFail() { + Storage storageMock = EasyMock.createMock(Storage.class); + EasyMock.expect(storageMock.list(BUCKET_NAME)).andReturn(BLOB_PAGE); + for (BlobInfo info : BLOB_LIST) { + EasyMock.expect(storageMock.delete(BUCKET_NAME, info.name())).andReturn(true); + } + EasyMock.expect(storageMock.delete(BUCKET_NAME)).andThrow(FATAL_EXCEPTION); + EasyMock.replay(storageMock); + thrown.expect(StorageException.class); + try { + RemoteGcsHelper.forceDelete(storageMock, BUCKET_NAME); + } finally { + EasyMock.verify(storageMock); + } + } + @Test public void testCreateFromStream() { RemoteGcsHelper helper = RemoteGcsHelper.create(PROJECT_ID, JSON_KEY_STREAM);