diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueApi.java index 7f208bf388..206bd23d86 100644 --- a/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueApi.java +++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueApi.java @@ -57,6 +57,29 @@ public interface QueueApi { FluentIterable list(); FluentIterable list(ListQueuesOptions options); + + /** + * The GetQueueUrl action returns the Uniform Resource Locater (URL) of a + * queue. This action provides a simple way to retrieve the URL of an SQS + * queue. + * + * @param queueName + * The name of an existing queue. + * @return uri of the queue or null if not found + */ + URI get(String queueName); + + /** + * like {@link #get(String)}, except specifying the owner of the queue. + * + * To access a queue that belongs to another AWS account, use the + * QueueOwnerAWSAccountId parameter to specify the account ID of the queue's + * owner. The queue's owner must grant you permission to access the queue. + * + * @param accountId + * @return The AWS account ID of the account that created the queue. + */ + URI getInAccount(String queueName, String accountId); /** * The CreateQueue action creates a new queue. diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueAsyncApi.java b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueAsyncApi.java index c0a839060c..3c8dbf7f5b 100644 --- a/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueAsyncApi.java +++ b/apis/sqs/src/main/java/org/jclouds/sqs/features/QueueAsyncApi.java @@ -83,6 +83,27 @@ public interface QueueAsyncApi { @ResponseParser(RegexListQueuesResponseHandler.class) ListenableFuture> list(ListQueuesOptions options); + /** + * @see QueueApi#get(String) + */ + @POST + @Path("/") + @FormParams(keys = ACTION, values = "GetQueueUrl") + @ResponseParser(RegexQueueHandler.class) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture get(@FormParam("QueueName") String queueName); + + /** + * @see QueueApi#getInAccount + */ + @POST + @Path("/") + @FormParams(keys = ACTION, values = "GetQueueUrl") + @ResponseParser(RegexQueueHandler.class) + @ExceptionParser(ReturnNullOnNotFoundOr404.class) + ListenableFuture getInAccount(@FormParam("QueueName") String queueName, + @FormParam("QueueOwnerAWSAccountId") String accountId); + /** * @see QueueApi#create */ diff --git a/apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java b/apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java index e191f44cac..c4b541ea7f 100644 --- a/apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java +++ b/apis/sqs/src/main/java/org/jclouds/sqs/xml/internal/BaseRegexQueueHandler.java @@ -38,7 +38,7 @@ import com.google.common.collect.ImmutableSet.Builder; */ @Singleton public class BaseRegexQueueHandler { - protected final Pattern pattern = Pattern.compile("(https://[\\S&&[^<]]+)"); + protected final Pattern pattern = Pattern.compile("(https?://[\\S&&[^<]]+)"); public FluentIterable parse(String in) { Builder queues = ImmutableSet. builder(); diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiLiveTest.java index b1aa629840..07deb5f006 100644 --- a/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiLiveTest.java +++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/PermissionApiLiveTest.java @@ -18,7 +18,6 @@ */ package org.jclouds.sqs.features; -import static com.google.common.collect.Iterables.get; import static org.jclouds.concurrent.MoreExecutors.sameThreadExecutor; import static org.jclouds.providers.AnonymousProviderMetadata.forClientMappedToAsyncClientOnEndpoint; import static org.jclouds.sqs.reference.SQSParameters.ACTION; @@ -42,7 +41,6 @@ import org.jclouds.sqs.xml.ValueHandler; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import com.google.common.base.Splitter; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Module; @@ -84,7 +82,7 @@ public class PermissionApiLiveTest extends BaseSQSApiLiveTest { QueueAttributes attributes = api().getQueueApi().getAttributes(queue); assertNoPermissions(queue); - String accountToAuthorize = getAccountToAuthorize(queue); + String accountToAuthorize = getOwner(queue); api().getPermissionApiForQueue(queue).addPermissionToAccount("fubar", Action.GET_QUEUE_ATTRIBUTES, accountToAuthorize); @@ -97,10 +95,6 @@ public class PermissionApiLiveTest extends BaseSQSApiLiveTest { } } - protected String getAccountToAuthorize(URI queue) { - return get(Splitter.on('/').split(queue.getPath()), 1); - } - @Test(dependsOnMethods = "testAddAnonymousPermission") public void testRemovePermission() throws InterruptedException { for (URI queue : queues) { diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiExpectTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiExpectTest.java index a9b09a1c4f..c17691ce9a 100644 --- a/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiExpectTest.java +++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiExpectTest.java @@ -19,6 +19,9 @@ package org.jclouds.sqs.features; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; + +import java.net.URI; import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpResponse; @@ -36,6 +39,71 @@ import com.google.common.collect.ImmutableSet; */ @Test(groups = "unit", testName = "QueueApiExpectTest") public class QueueApiExpectTest extends BaseSQSApiExpectTest { + public HttpRequest getQueueUrl = HttpRequest.builder() + .method("POST") + .endpoint("https://sqs.us-east-1.amazonaws.com/") + .addHeader("Host", "sqs.us-east-1.amazonaws.com") + .addFormParam("Action", "GetQueueUrl") + .addFormParam("QueueName", "queueName") + .addFormParam("Signature", "ZjHLpNl6NLqK%2BsqOyEFqEJMWGeOLuNBd3%2B0Z9RGPYWU%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2011-10-01") + .addFormParam("AWSAccessKeyId", "identity").build(); + + public void testGetQueueUrlWhenResponseIs2xx() throws Exception { + + HttpResponse getQueueUrlResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/get_queue_url.xml", "text/xml")).build(); + + + SQSApi apiWhenExist = requestSendsResponse(getQueueUrl, getQueueUrlResponse); + + assertEquals(apiWhenExist.getQueueApi().get("queueName"), URI.create("http://sqs.us-east-1.amazonaws.com/123456789012/testQueue")); + } + + public HttpRequest getQueueUrlByOwner = HttpRequest.builder() + .method("POST") + .endpoint("https://sqs.us-east-1.amazonaws.com/") + .addHeader("Host", "sqs.us-east-1.amazonaws.com") + .addFormParam("Action", "GetQueueUrl") + .addFormParam("QueueName", "queueName") + .addFormParam("QueueOwnerAWSAccountId", "120908098979") + .addFormParam("Signature", "O0E%2B3jh2vN6bKqmb4%2FXPTHUmPO1iat9o8YnIFH463g8%3D") + .addFormParam("SignatureMethod", "HmacSHA256") + .addFormParam("SignatureVersion", "2") + .addFormParam("Timestamp", "2009-11-08T15%3A54%3A08.897Z") + .addFormParam("Version", "2011-10-01") + .addFormParam("AWSAccessKeyId", "identity").build(); + + public void testGetQueueUrlByOwnerWhenResponseIs2xx() throws Exception { + + HttpResponse getQueueUrlResponse = HttpResponse.builder() + .statusCode(200) + .payload(payloadFromResourceWithContentType("/get_queue_url.xml", "text/xml")).build(); + + + SQSApi apiWhenExist = requestSendsResponse(getQueueUrlByOwner, getQueueUrlResponse); + + assertEquals(apiWhenExist.getQueueApi().getInAccount("queueName", "120908098979"), URI.create("http://sqs.us-east-1.amazonaws.com/123456789012/testQueue")); + } + + // when the queue doesn't exist, or you don't have access to it + public void testGetQueueUrlByOwnerWhenResponseIs400ReturnsNull() throws Exception { + + HttpResponse getQueueUrlResponse = HttpResponse.builder() + .statusCode(400) + .payload( + payloadFromStringWithContentType( + "SenderAWS.SimpleQueueService.NonExistentQueueThe specified queue does not exist or you do not have access to it.194a169f-4483-5bb1-8cb6-5e4ac865909a", + "text/xml")).build(); + + SQSApi apiWhenExist = requestSendsResponse(getQueueUrlByOwner, getQueueUrlResponse); + + assertNull(apiWhenExist.getQueueApi().getInAccount("queueName", "120908098979")); + } public HttpRequest createQueue = HttpRequest.builder() .method("POST") diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiLiveTest.java index 799ff2d887..1838163574 100644 --- a/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiLiveTest.java +++ b/apis/sqs/src/test/java/org/jclouds/sqs/features/QueueApiLiveTest.java @@ -21,9 +21,11 @@ package org.jclouds.sqs.features; import static com.google.common.collect.Iterables.getLast; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; import java.net.URI; import java.util.Map; +import java.util.UUID; import org.jclouds.sqs.internal.BaseSQSApiLiveTest; import org.testng.annotations.Test; @@ -55,13 +57,32 @@ public class QueueApiLiveTest extends BaseSQSApiLiveTest { assertQueueInList(region, queue); } } - + + @Test + public void testGracefulNoQueue() throws InterruptedException { + assertNull(api().getQueueApi().get(UUID.randomUUID().toString())); + } + @Test public void testCanRecreateQueueGracefully() throws InterruptedException { recreateQueueInRegion(prefix, null); recreateQueueInRegion(prefix, null); } + @Test(dependsOnMethods = "testCanRecreateQueueGracefully") + public void testGet() { + for (URI queue : queues) { + assertEquals(queue, api().getQueueApi().get(prefix)); + } + } + + @Test(dependsOnMethods = "testCanRecreateQueueGracefully") + public void testGetInAccount() { + for (URI queue : queues) { + assertEquals(api().getQueueApi().getInAccount(prefix, getOwner(queue)), queue); + } + } + @Test(dependsOnMethods = "testCanRecreateQueueGracefully") public void testGetQueueAttributes() { for (URI queue : queues) { diff --git a/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiLiveTest.java b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiLiveTest.java index 96031c8fa5..e2384e2197 100644 --- a/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiLiveTest.java +++ b/apis/sqs/src/test/java/org/jclouds/sqs/internal/BaseSQSApiLiveTest.java @@ -18,6 +18,7 @@ */ package org.jclouds.sqs.internal; +import static com.google.common.collect.Iterables.get; import static com.google.common.collect.Iterables.getLast; import static org.jclouds.sqs.options.ListQueuesOptions.Builder.queuePrefix; import static org.testng.Assert.assertNotNull; @@ -39,6 +40,7 @@ import org.jclouds.sqs.features.QueueApi; import org.testng.annotations.AfterClass; import org.testng.annotations.Test; +import com.google.common.base.Splitter; import com.google.common.collect.FluentIterable; import com.google.common.collect.Sets; import com.google.common.reflect.TypeToken; @@ -59,6 +61,10 @@ public class BaseSQSApiLiveTest extends BaseContextLiveTest queues = Sets.newHashSet(); + protected String getOwner(URI queue) { + return get(Splitter.on('/').split(queue.getPath()), 1); + } + protected String recreateQueueInRegion(String queueName, String region) { QueueApi api = api().getQueueApiForRegion(region); FluentIterable result = api.list(queuePrefix(queueName)); diff --git a/apis/sqs/src/test/resources/get_queue_url.xml b/apis/sqs/src/test/resources/get_queue_url.xml new file mode 100644 index 0000000000..8e26510f57 --- /dev/null +++ b/apis/sqs/src/test/resources/get_queue_url.xml @@ -0,0 +1,8 @@ + + + http://sqs.us-east-1.amazonaws.com/123456789012/testQueue + + + 470a6f13-2ed9-4181-ad8a-2fdea142988e + + \ No newline at end of file