From 863c57270d177fd0ccbc0dd6b84083ab2777f983 Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Fri, 8 Jan 2016 17:14:02 -0800 Subject: [PATCH 1/2] Create simple forceDelete that can be used on AppEngine --- .../storage/testing/RemoteGcsHelper.java | 17 ++++++++++ .../gcloud/storage/RemoteGcsHelperTest.java | 31 +++++++++++++++++++ 2 files changed, 48 insertions(+) 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..e8ac3916e3e5 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 @@ -88,6 +88,23 @@ public static Boolean forceDelete(Storage storage, String bucket, long timeout, } } + /** + * Deletes a bucket, even if non-empty. Objects in the bucket are listed and deleted until bucket + * deletion succeeds. This method can be used to delete buckets from within App Engine. Note that + * this method does not set a timeout. + * + * @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) throws StorageException { + try { + new DeleteBucketTask(storage, bucket).call(); + } catch (Exception e) { + throw (StorageException) e; + } + } + /** * Returns a bucket name generated using a random UUID. */ 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..5d39c5c8eac5 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,37 @@ public void testForceDeleteFail() throws InterruptedException, ExecutionExceptio } } + + @Test + public void testForceDeleteNoTimeout() throws Exception { + 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() throws Exception { + 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); From 33f6ad862077eb45a9dec040e45a899cc462cbf6 Mon Sep 17 00:00:00 2001 From: Ajay Kannan Date: Mon, 11 Jan 2016 09:32:27 -0800 Subject: [PATCH 2/2] Use runtime exceptions for DeleteBucketTask.call() --- .../storage/testing/RemoteGcsHelper.java | 26 ++++++++++--------- .../gcloud/storage/RemoteGcsHelperTest.java | 5 ++-- 2 files changed, 16 insertions(+), 15 deletions(-) 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 e8ac3916e3e5..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 @@ -89,20 +92,14 @@ public static Boolean forceDelete(Storage storage, String bucket, long timeout, } /** - * Deletes a bucket, even if non-empty. Objects in the bucket are listed and deleted until bucket - * deletion succeeds. This method can be used to delete buckets from within App Engine. Note that - * this method does not set a 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) throws StorageException { - try { - new DeleteBucketTask(storage, bucket).call(); - } catch (Exception e) { - throw (StorageException) e; - } + public static void forceDelete(Storage storage, String bucket) { + new DeleteBucketTask(storage, bucket).call(); } /** @@ -174,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()); @@ -184,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 5d39c5c8eac5..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,9 +140,8 @@ public void testForceDeleteFail() throws InterruptedException, ExecutionExceptio } } - @Test - public void testForceDeleteNoTimeout() throws Exception { + public void testForceDeleteNoTimeout() { Storage storageMock = EasyMock.createMock(Storage.class); EasyMock.expect(storageMock.list(BUCKET_NAME)).andReturn(BLOB_PAGE); for (BlobInfo info : BLOB_LIST) { @@ -155,7 +154,7 @@ public void testForceDeleteNoTimeout() throws Exception { } @Test - public void testForceDeleteNoTimeoutFail() throws Exception { + public void testForceDeleteNoTimeoutFail() { Storage storageMock = EasyMock.createMock(Storage.class); EasyMock.expect(storageMock.list(BUCKET_NAME)).andReturn(BLOB_PAGE); for (BlobInfo info : BLOB_LIST) {