mirror of https://github.com/apache/jclouds.git
added tests and attributes calls to sqs
This commit is contained in:
parent
a0b1ffb625
commit
b0626e3324
|
@ -19,6 +19,7 @@
|
|||
package org.jclouds.sqs;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -61,27 +62,27 @@ public interface SQSApi {
|
|||
Set<URI> listQueuesInRegion(@Nullable String region, ListQueuesOptions options);
|
||||
|
||||
/**
|
||||
*
|
||||
* The CreateQueue action creates a new queue.
|
||||
* <p/>
|
||||
*
|
||||
* When you request CreateQueue, you provide a name for the queue. To
|
||||
* successfully create a new queue, you must provide a name that is unique
|
||||
* within the scope of your own queues. If you provide the name of an
|
||||
* existing queue, a new queue isn't created and an error isn't returned.
|
||||
* Instead, the request succeeds and the queue URL for the existing queue is
|
||||
* returned (for more information about queue URLs, see Queue and Message
|
||||
* Identifiers in the Amazon SQS Developer Guide). Exception: if you provide
|
||||
* a value for DefaultVisibilityTimeout that is different from the value for
|
||||
* the existing queue, you receive an error.
|
||||
* <h3>Note</h3>
|
||||
* within the scope of your own queues.
|
||||
*
|
||||
* <h4>Note</h4>
|
||||
*
|
||||
* If you delete a queue, you must wait at least 60 seconds before creating a
|
||||
* queue with the same name.
|
||||
* <p/>
|
||||
* A default value for the queue's visibility timeout (30 seconds) is set
|
||||
* when the queue is created. You can override this value with the
|
||||
* DefaultVisibilityTimeout request parameter. For more information, see
|
||||
* Visibility Timeout in the Amazon SQS Developer Guide.
|
||||
*
|
||||
* If you provide the name of an existing queue, along with the exact names
|
||||
* and values of all the queue's attributes, CreateQueue returns the queue
|
||||
* URL for the existing queue. If the queue name, attribute names, or
|
||||
* attribute values do not match an existing queue, CreateQueue returns an
|
||||
* error.
|
||||
*
|
||||
* <h4>Tip</h4>
|
||||
*
|
||||
* Use GetQueueUrl to get a queue's URL. GetQueueUrl requires only the
|
||||
* QueueName parameter.
|
||||
*
|
||||
* @param region
|
||||
* Queues are Region-specific.
|
||||
|
@ -89,29 +90,39 @@ public interface SQSApi {
|
|||
* The name to use for the queue created. Constraints: Maximum 80
|
||||
* characters; alphanumeric characters, hyphens (-), and
|
||||
* underscores (_) are allowed.
|
||||
* @param options
|
||||
* like the visibility timeout (in seconds) to use for this queue.
|
||||
*/
|
||||
// this will gracefully attempt to resolve name issues
|
||||
@Timeout(duration = 61, timeUnit = TimeUnit.SECONDS)
|
||||
URI createQueueInRegion(@Nullable String region, String queueName);
|
||||
|
||||
/**
|
||||
* same as {@link #createQueueInRegion(String, String)} except you can
|
||||
* control options such as delay seconds.
|
||||
*
|
||||
* @param options
|
||||
* options such as delay seconds
|
||||
* @see #createQueueInRegion(String, String)
|
||||
*/
|
||||
@Timeout(duration = 61, timeUnit = TimeUnit.SECONDS)
|
||||
URI createQueueInRegion(@Nullable String region, String queueName, CreateQueueOptions options);
|
||||
|
||||
/**
|
||||
* The DeleteQueue action deletes the queue specified by the queue URL,
|
||||
* regardless of whether the queue is empty. If the specified queue does not
|
||||
* exist, SQS returns a successful response. <h3>
|
||||
* Caution</h3>
|
||||
* exist, SQS returns a successful response.
|
||||
*
|
||||
* <h4>Caution</h4>
|
||||
*
|
||||
* Use DeleteQueue with care; once you delete your queue, any messages in the
|
||||
* queue are no longer available.
|
||||
* <p/>
|
||||
*
|
||||
* When you delete a queue, the deletion process takes up to 60 seconds.
|
||||
* Requests you send involving that queue during the 60 seconds might
|
||||
* succeed. For example, a SendMessage request might succeed, but after the
|
||||
* 60 seconds, the queue and that message you sent no longer exist. Also,
|
||||
* when you delete a queue, you must wait at least 60 seconds before creating
|
||||
* a queue with the same name.
|
||||
* <p/>
|
||||
*
|
||||
* We reserve the right to delete queues that have had no activity for more
|
||||
* than 30 days. For more information, see About SQS Queues in the Amazon SQS
|
||||
* Developer Guide.
|
||||
|
@ -121,37 +132,204 @@ public interface SQSApi {
|
|||
*/
|
||||
void deleteQueue(URI queue);
|
||||
|
||||
/**
|
||||
* The DeleteMessage action deletes the specified message from the specified
|
||||
* queue. You specify the message by using the message's receipt handle and
|
||||
* not the message ID you received when you sent the message. Even if the
|
||||
* message is locked by another reader due to the visibility timeout setting,
|
||||
* it is still deleted from the queue. If you leave a message in the queue
|
||||
* for more than 4 days, SQS automatically deletes it.
|
||||
*
|
||||
* <h4>Note</h4>
|
||||
*
|
||||
* The receipt handle is associated with a specific instance of receiving the
|
||||
* message. If you receive a message more than once, the receipt handle you
|
||||
* get each time you receive the message is different. When you request
|
||||
* DeleteMessage, if you don't provide the most recently received receipt
|
||||
* handle for the message, the request will still succeed, but the message
|
||||
* might not be deleted.
|
||||
*
|
||||
* <h4>Important</h4>
|
||||
*
|
||||
* It is possible you will receive a message even after you have deleted it.
|
||||
* This might happen on rare occasions if one of the servers storing a copy
|
||||
* of the message is unavailable when you request to delete the message. The
|
||||
* copy remains on the server and might be returned to you again on a
|
||||
* subsequent receive request. You should create your system to be idempotent
|
||||
* so that receiving a particular message more than once is not a problem.
|
||||
*
|
||||
* @param queue
|
||||
* the queue the message is in
|
||||
* @param receiptHandle
|
||||
* The receipt handle associated with the message you want to
|
||||
* delete.
|
||||
*/
|
||||
void deleteMessage(URI queue, String receiptHandle);
|
||||
|
||||
/**
|
||||
* The SendMessage action delivers a message to the specified queue. The
|
||||
* maximum allowed message size is 8 KB.
|
||||
* <p/>
|
||||
* Important
|
||||
* <p/>
|
||||
* maximum allowed message size is 64 KB.
|
||||
*
|
||||
* <h4>Important</h4>
|
||||
*
|
||||
* The following list shows the characters (in Unicode) allowed in your
|
||||
* message, according to the W3C XML specification (for more information, go
|
||||
* to http://www.w3.org/TR/REC-xml/#charsets). If you send any characters not
|
||||
* included in the list, your request will be rejected.
|
||||
* <p/>
|
||||
* #x9 | #xA | #xD | [#x20 to #xD7FF] | [#xE000 to #xFFFD] | [#x10000 to
|
||||
* #x10FFFF]
|
||||
*
|
||||
*
|
||||
* {@code #x9 | #xA | #xD | [#x20 to #xD7FF] | [#xE000 to #xFFFD] | [#x10000 to #x10FFFF]}
|
||||
*
|
||||
* @param queue
|
||||
* queue you want to send to
|
||||
*
|
||||
* @param message
|
||||
* The message to send. Type: String maximum 8 KB in size. For a
|
||||
* list of allowed characters, see the preceding important note
|
||||
* @return md5 of the content sent
|
||||
* Type: String maximum 64 KB in size. For a list of allowed
|
||||
* characters, see the preceding important note.
|
||||
* @return id of the message and md5 of the content sent
|
||||
*/
|
||||
MessageIdAndMD5 sendMessage(URI queue, String message);
|
||||
|
||||
/**
|
||||
* same as {@link #sendMessage(URI, String)} except you can control options
|
||||
* such as delay seconds.
|
||||
*
|
||||
* @param options
|
||||
* options such as delay seconds
|
||||
* @see #sendMessage(URI, String)
|
||||
*/
|
||||
MessageIdAndMD5 sendMessage(URI queue, String message, SendMessageOptions options);
|
||||
|
||||
/**
|
||||
* The ReceiveMessage action retrieves one or more messages from the
|
||||
* specified queue. The ReceiveMessage action does not delete the message
|
||||
* after it is retrieved. To delete a message, you must use the DeleteMessage
|
||||
* action. For more information about message deletion in the message life
|
||||
* cycle, see Message Lifecycle.
|
||||
*
|
||||
* <h4>Note</h4>
|
||||
*
|
||||
* Due to the distributed nature of the queue, a weighted random set of
|
||||
* machines is sampled on a ReceiveMessage call. That means only the messages
|
||||
* on the sampled machines are returned. If the number of messages in the
|
||||
* queue is small (less than 1000), it is likely you will get fewer messages
|
||||
* than you requested per ReceiveMessage call. If the number of messages in
|
||||
* the queue is extremely small, you might not receive any messages in a
|
||||
* particular ReceiveMessage response; in which case you should repeat the
|
||||
* request.
|
||||
*
|
||||
* @param queue
|
||||
* from where you are receiving messages
|
||||
* @return message including the receipt handle you can use to delete it
|
||||
*/
|
||||
Message receiveMessage(URI queue);
|
||||
|
||||
/**
|
||||
* same as {@link #receiveMessage(URI)} except you can provide options like
|
||||
* VisibilityTimeout parameter in your request, which will be applied to the
|
||||
* messages that SQS returns in the response. If you do not include the
|
||||
* parameter, the overall visibility timeout for the queue is used for the
|
||||
* returned messages.
|
||||
*
|
||||
* @param options
|
||||
* options such as VisibilityTimeout
|
||||
* @see #receiveMessage(URI)
|
||||
*/
|
||||
Message receiveMessage(URI queue, ReceiveMessageOptions options);
|
||||
|
||||
/**
|
||||
* same as {@link #receiveMessage(URI)} except you can receive multiple
|
||||
* messages.
|
||||
*
|
||||
* @param max
|
||||
* maximum messages to receive, current limit is 10
|
||||
* @see #receiveMessage(URI)
|
||||
*/
|
||||
Set<Message> receiveMessages(URI queue, int max);
|
||||
|
||||
/**
|
||||
* returns all attributes of a queue.
|
||||
*
|
||||
* @param queue
|
||||
* queue to get the attributes of
|
||||
*/
|
||||
Map<String, String> getQueueAttributes(URI queue);
|
||||
|
||||
/**
|
||||
* The SetQueueAttributes action sets one attribute of a queue per request.
|
||||
* When you change a queue's attributes, the change can take up to 60 seconds
|
||||
* to propagate throughout the SQS system.
|
||||
*
|
||||
* @param queue
|
||||
* queue to set the attribute on
|
||||
* @param name
|
||||
*
|
||||
* The name of the attribute you want to set.
|
||||
*
|
||||
* VisibilityTimeout - The length of time (in seconds) that a
|
||||
* message received from a queue will be invisible to other
|
||||
* receiving components when they ask to receive messages. For more
|
||||
* information about VisibilityTimeout, see Visibility Timeout in
|
||||
* the Amazon SQS Developer Guide.
|
||||
*
|
||||
* Policy - The formal description of the permissions for a
|
||||
* resource. For more information about Policy, see Basic Policy
|
||||
* Structure in the Amazon SQS Developer Guide.
|
||||
*
|
||||
* MaximumMessageSize - The limit of how many bytes a message can
|
||||
* contain before Amazon SQS rejects it.
|
||||
*
|
||||
* MessageRetentionPeriod - The number of seconds Amazon SQS
|
||||
* retains a message.
|
||||
*
|
||||
* DelaySeconds - The time in seconds that the delivery of all
|
||||
* messages in the queue will be delayed.
|
||||
* @param value
|
||||
* The value of the attribute you want to set. To delete a queue's
|
||||
* access control policy, set the policy to "".
|
||||
*
|
||||
* Constraints: Constraints are specific for each value.
|
||||
*
|
||||
* VisibilityTimeout - An integer from 0 to 43200 (12 hours). The
|
||||
* default for this attribute is 30 seconds.
|
||||
*
|
||||
* Policy - A valid form-url-encoded policy. For more information
|
||||
* about policy structure, see Basic Policy Structure in the Amazon
|
||||
* SQS Developer Guide. For more information about
|
||||
* form-url-encoding, see
|
||||
* http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2.1.
|
||||
*
|
||||
* MaximumMessageSize - An integer from 1024 bytes (1 KiB) up to
|
||||
* 65536 bytes (64 KiB). The default for this attribute is 65536
|
||||
* (64 KiB).
|
||||
*
|
||||
* MessageRetentionPeriod - Integer representing seconds, from 60
|
||||
* (1 minute) to 1209600 (14 days). The default for this attribute
|
||||
* is 345600 (4 days).
|
||||
*
|
||||
* DelaySeconds - An integer from 0 to 900 (15 minutes). The
|
||||
* default for this attribute is 0.
|
||||
*/
|
||||
void setQueueAttribute(URI queue, String name, String value);
|
||||
|
||||
/**
|
||||
* returns some attributes of a queue.
|
||||
*
|
||||
* @param queue
|
||||
* queue to get the attributes of
|
||||
*/
|
||||
Map<String, String> getQueueAttributes(URI queue, Iterable<String> attributeNames);
|
||||
|
||||
/**
|
||||
* same as {@link #receiveMessages(URI, int)} except you can provide options
|
||||
* like VisibilityTimeout parameter in your request, which will be applied to
|
||||
* the messages that SQS returns in the response. If you do not include the
|
||||
* parameter, the overall visibility timeout for the queue is used for the
|
||||
* returned messages.
|
||||
*
|
||||
* @param options
|
||||
* options such as VisibilityTimeout
|
||||
* @see #receiveMessages(URI, int)
|
||||
*/
|
||||
Set<Message> receiveMessages(URI queue, int max, ReceiveMessageOptions options);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.jclouds.sqs;
|
|||
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
|
||||
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
|
||||
import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_MAX_RETRIES;
|
||||
import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_RETRY_INTERVAL;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
@ -62,6 +64,8 @@ public class SQSApiMetadata extends BaseRestApiMetadata {
|
|||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = BaseRestApiMetadata.defaultProperties();
|
||||
properties.setProperty(CREATE_QUEUE_MAX_RETRIES, "60");
|
||||
properties.setProperty(CREATE_QUEUE_RETRY_INTERVAL, "1000");
|
||||
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
|
||||
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
|
||||
return properties;
|
||||
|
|
|
@ -22,6 +22,7 @@ import static org.jclouds.sqs.reference.SQSParameters.ACTION;
|
|||
import static org.jclouds.sqs.reference.SQSParameters.VERSION;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ws.rs.FormParam;
|
||||
|
@ -32,18 +33,21 @@ import org.jclouds.Constants;
|
|||
import org.jclouds.aws.filters.FormSigner;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull;
|
||||
import org.jclouds.rest.annotations.BinderParam;
|
||||
import org.jclouds.rest.annotations.EndpointParam;
|
||||
import org.jclouds.rest.annotations.FormParams;
|
||||
import org.jclouds.rest.annotations.RequestFilters;
|
||||
import org.jclouds.rest.annotations.ResponseParser;
|
||||
import org.jclouds.rest.annotations.VirtualHost;
|
||||
import org.jclouds.rest.annotations.XMLResponseParser;
|
||||
import org.jclouds.sqs.binders.BindAttributeNamesToIndexedFormParams;
|
||||
import org.jclouds.sqs.domain.Message;
|
||||
import org.jclouds.sqs.domain.MessageIdAndMD5;
|
||||
import org.jclouds.sqs.options.CreateQueueOptions;
|
||||
import org.jclouds.sqs.options.ListQueuesOptions;
|
||||
import org.jclouds.sqs.options.ReceiveMessageOptions;
|
||||
import org.jclouds.sqs.options.SendMessageOptions;
|
||||
import org.jclouds.sqs.xml.AttributesHandler;
|
||||
import org.jclouds.sqs.xml.MessageHandler;
|
||||
import org.jclouds.sqs.xml.ReceiveMessageResponseHandler;
|
||||
import org.jclouds.sqs.xml.RegexListQueuesResponseHandler;
|
||||
|
@ -114,6 +118,14 @@ public interface SQSAsyncApi {
|
|||
@FormParams(keys = ACTION, values = "DeleteQueue")
|
||||
ListenableFuture<Void> deleteQueue(@EndpointParam URI queue);
|
||||
|
||||
/**
|
||||
* @see SQSApi#deleteMessage
|
||||
*/
|
||||
@POST
|
||||
@Path("/")
|
||||
@FormParams(keys = ACTION, values = "DeleteMessage")
|
||||
ListenableFuture<Void> deleteMessage(@EndpointParam URI queue, @FormParam("ReceiptHandle") String receiptHandle);
|
||||
|
||||
/**
|
||||
* @see SQSApi#sendMessage
|
||||
*/
|
||||
|
@ -151,6 +163,34 @@ public interface SQSAsyncApi {
|
|||
@XMLResponseParser(MessageHandler.class)
|
||||
ListenableFuture<Message> receiveMessage(@EndpointParam URI queue, ReceiveMessageOptions options);
|
||||
|
||||
/**
|
||||
* @see SQSApi#getQueueAttributes(URI)
|
||||
*/
|
||||
@POST
|
||||
@Path("/")
|
||||
@FormParams(keys = { ACTION, "AttributeName.1" }, values = { "GetQueueAttributes", "All" })
|
||||
@XMLResponseParser(AttributesHandler.class)
|
||||
ListenableFuture<Map<String, String>> getQueueAttributes(@EndpointParam URI queue);
|
||||
|
||||
/**
|
||||
* @see SQSApi#getQueueAttributes(URI, Iterable)
|
||||
*/
|
||||
@POST
|
||||
@Path("/")
|
||||
@FormParams(keys = ACTION, values = "GetQueueAttributes")
|
||||
@XMLResponseParser(AttributesHandler.class)
|
||||
ListenableFuture<Map<String, String>> getQueueAttributes(@EndpointParam URI queue,
|
||||
@BinderParam(BindAttributeNamesToIndexedFormParams.class) Iterable<String> attributeNames);
|
||||
|
||||
/**
|
||||
* @see SQSApi#setQueueAttribute
|
||||
*/
|
||||
@POST
|
||||
@Path("/")
|
||||
@FormParams(keys = ACTION, values = "SetQueueAttributes")
|
||||
ListenableFuture<Void> setQueueAttribute(@EndpointParam URI queue, @FormParam("Attribute.Name") String name,
|
||||
@FormParam("Attribute.Value") String value);
|
||||
|
||||
/**
|
||||
* @see SQSApi#receiveMessages
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.binders;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.rest.Binder;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableMultimap.Builder;
|
||||
|
||||
/**
|
||||
* Binds the Iterable<String> to form parameters named with AttributeName.index
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
public class BindAttributeNamesToIndexedFormParams implements Binder {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <R extends HttpRequest> R bindToRequest(R request, Object input) {
|
||||
Iterable<?> values = Iterable.class.cast(checkNotNull(input, "attributeNames"));
|
||||
Builder<String, String> builder = ImmutableMultimap.builder();
|
||||
int i = 0;
|
||||
for (Object o : values) {
|
||||
builder.put("AttributeName." + (i++ + 1), o.toString());
|
||||
}
|
||||
ImmutableMultimap<String, String> forms = builder.build();
|
||||
return (R) (forms.size() == 0 ? request : request.toBuilder().replaceFormParams(forms).build());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.config;
|
||||
|
||||
|
||||
/**
|
||||
* Configuration properties and constants used in SQS connections.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public interface SQSProperties {
|
||||
|
||||
/**
|
||||
* Integer property.
|
||||
* <p/>
|
||||
* When creating a queue, you can encounter
|
||||
* {@code AWS.SimpleQueueService.QueueDeletedRecently}, which is typically a
|
||||
* resolvable error. default tries are 60,
|
||||
*/
|
||||
public static final String CREATE_QUEUE_MAX_RETRIES = "jclouds.sqs.create-queue.max-retries";
|
||||
|
||||
/**
|
||||
* Long property.
|
||||
* <p/>
|
||||
* When creating a queue, you can encounter
|
||||
* {@code AWS.SimpleQueueService.QueueDeletedRecently}, which is typically a
|
||||
* resolvable error. default interval between tries is 1000 milliseconds (1
|
||||
* second).
|
||||
*/
|
||||
public static final String CREATE_QUEUE_RETRY_INTERVAL = "jclouds.sqs.create-queue.retry-interval";
|
||||
|
||||
}
|
|
@ -19,9 +19,16 @@
|
|||
package org.jclouds.sqs.config;
|
||||
|
||||
import org.jclouds.aws.config.FormSigningRestClientModule;
|
||||
import org.jclouds.http.HttpErrorHandler;
|
||||
import org.jclouds.http.HttpRetryHandler;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
import org.jclouds.http.annotation.Redirection;
|
||||
import org.jclouds.http.annotation.ServerError;
|
||||
import org.jclouds.rest.ConfiguresRestClient;
|
||||
import org.jclouds.sqs.SQSApi;
|
||||
import org.jclouds.sqs.SQSAsyncApi;
|
||||
import org.jclouds.sqs.handlers.ParseSQSErrorFromXmlContent;
|
||||
import org.jclouds.sqs.handlers.SQSErrorRetryHandler;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
|
@ -37,4 +44,16 @@ public class SQSRestClientModule extends FormSigningRestClientModule<SQSApi, SQS
|
|||
super(TypeToken.of(SQSApi.class), TypeToken.of(SQSAsyncApi.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindErrorHandlers() {
|
||||
bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(ParseSQSErrorFromXmlContent.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(ParseSQSErrorFromXmlContent.class);
|
||||
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseSQSErrorFromXmlContent.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindRetryHandlers() {
|
||||
bind(HttpRetryHandler.class).annotatedWith(ClientError.class).to(SQSErrorRetryHandler.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.handlers;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.aws.domain.AWSError;
|
||||
import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
|
||||
import org.jclouds.aws.util.AWSUtils;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.rest.ResourceNotFoundException;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
@Singleton
|
||||
public class ParseSQSErrorFromXmlContent extends ParseAWSErrorFromXmlContent {
|
||||
protected Set<String> resourceNotFoundCodes = ImmutableSet.of("AWS.SimpleQueueService.NonExistentQueue");
|
||||
protected Set<String> illegalStateCodes = ImmutableSet.of("AWS.SimpleQueueService.QueueDeletedRecently",
|
||||
"AWS.SimpleQueueService.QueueNameExists");
|
||||
protected Set<String> illegalArgumentCodes = ImmutableSet.of("InvalidAttributeName", "ReadCountOutOfRange",
|
||||
"InvalidMessageContents", "MessageTooLong");
|
||||
|
||||
@Inject
|
||||
public ParseSQSErrorFromXmlContent(AWSUtils utils) {
|
||||
super(utils);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Exception refineException(HttpCommand command, HttpResponse response, Exception exception, AWSError error,
|
||||
String message) {
|
||||
String errorCode = (error != null && error.getCode() != null) ? error.getCode() : null;
|
||||
if (resourceNotFoundCodes.contains(errorCode))
|
||||
exception = new ResourceNotFoundException(message, exception);
|
||||
else if (illegalStateCodes.contains(errorCode))
|
||||
exception = new IllegalStateException(message, exception);
|
||||
else if (illegalArgumentCodes.contains(errorCode))
|
||||
exception = new IllegalArgumentException(message, exception);
|
||||
else
|
||||
exception = super.refineException(command, response, exception, error, message);
|
||||
return exception;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.handlers;
|
||||
|
||||
import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_MAX_RETRIES;
|
||||
import static org.jclouds.sqs.config.SQSProperties.CREATE_QUEUE_RETRY_INTERVAL;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Named;
|
||||
|
||||
import org.jclouds.aws.domain.AWSError;
|
||||
import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
|
||||
import org.jclouds.aws.util.AWSUtils;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.annotation.ClientError;
|
||||
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class SQSErrorRetryHandler extends AWSClientErrorRetryHandler {
|
||||
|
||||
private final long retryInterval;
|
||||
private final int maxTries;
|
||||
|
||||
@Inject
|
||||
public SQSErrorRetryHandler(AWSUtils utils, BackoffLimitedRetryHandler backoffLimitedRetryHandler,
|
||||
@ClientError Set<String> retryableCodes, @Named(CREATE_QUEUE_MAX_RETRIES) int maxTries,
|
||||
@Named(CREATE_QUEUE_RETRY_INTERVAL) long retryInterval) {
|
||||
super(utils, backoffLimitedRetryHandler, retryableCodes);
|
||||
this.maxTries = maxTries;
|
||||
this.retryInterval = retryInterval;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean shouldRetryRequestOnError(HttpCommand command, HttpResponse response, AWSError error) {
|
||||
if ("AWS.SimpleQueueService.QueueDeletedRecently".equals(error.getCode())) {
|
||||
if (command.incrementFailureCount() - 1 < maxTries) {
|
||||
Uninterruptibles.sleepUninterruptibly(retryInterval, TimeUnit.MILLISECONDS);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return super.shouldRetryRequestOnError(command, response, error);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.xml;
|
||||
|
||||
import static org.jclouds.util.SaxUtils.currentOrNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.http.functions.ParseSax;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
|
||||
/**
|
||||
* @see <a href=
|
||||
* "http://docs.amazonwebservices.com/AWSSimpleQueueService/2011-10-01/APIReference/Query_QueryGetQueueAttributes.html"
|
||||
* />
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class AttributesHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Map<String, String>> {
|
||||
|
||||
private StringBuilder currentText = new StringBuilder();
|
||||
private Builder<String, String> builder = ImmutableMap.<String, String> builder();
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public Map<String, String> getResult() {
|
||||
try {
|
||||
return builder.build();
|
||||
} catch (NullPointerException e) {
|
||||
return null;
|
||||
} finally {
|
||||
builder = ImmutableMap.<String, String> builder();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String name, String qName) {
|
||||
if (qName.equals("Name")) {
|
||||
this.name = currentOrNull(currentText);
|
||||
} else if (qName.equals("Value")) {
|
||||
builder.put(this.name, currentOrNull(currentText));
|
||||
this.name = null;
|
||||
}
|
||||
currentText = new StringBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char ch[], int start, int length) {
|
||||
currentText.append(ch, start, length);
|
||||
}
|
||||
|
||||
}
|
|
@ -42,7 +42,7 @@ public class RegexQueueHandler extends BaseRegexQueueHandler implements Function
|
|||
private final ReturnStringIf2xx returnStringIf200;
|
||||
|
||||
@Inject
|
||||
RegexQueueHandler(ReturnStringIf2xx returnStringIf200) {
|
||||
public RegexQueueHandler(ReturnStringIf2xx returnStringIf200) {
|
||||
this.returnStringIf200 = returnStringIf200;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,13 @@ import java.net.URI;
|
|||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.sqs.internal.BaseSQSApiExpectTest;
|
||||
import org.jclouds.sqs.parse.CreateQueueResponseTest;
|
||||
import org.jclouds.sqs.parse.GetQueueAttributesResponseTest;
|
||||
import org.jclouds.sqs.parse.ReceiveMessageResponseTest;
|
||||
import org.jclouds.sqs.parse.SendMessageResponseTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
|
@ -37,7 +40,30 @@ import com.google.common.collect.Iterables;
|
|||
@Test(groups = "unit", testName = "SQSApiExpectTest")
|
||||
public class SQSApiExpectTest extends BaseSQSApiExpectTest {
|
||||
|
||||
HttpRequest sendMessage = HttpRequest.builder()
|
||||
public HttpRequest createQueue = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
.addFormParam("Action", "CreateQueue")
|
||||
.addFormParam("QueueName", "queueName")
|
||||
.addFormParam("Signature", "I7tmwiCzJ9cvw79pmlz1rOILh2C2ZV6OpLk23JGx6AU%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 testCreateQueueWhenResponseIs2xx() throws Exception {
|
||||
|
||||
HttpResponse createQueueResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResourceWithContentType("/create_queue.xml", "text/xml")).build();
|
||||
|
||||
SQSApi apiWhenExist = requestSendsResponse(createQueue, createQueueResponse);
|
||||
|
||||
assertEquals(apiWhenExist.createQueueInRegion(null, "queueName").toString(), new CreateQueueResponseTest().expected().toString());
|
||||
}
|
||||
|
||||
public HttpRequest sendMessage = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
|
@ -61,7 +87,7 @@ public class SQSApiExpectTest extends BaseSQSApiExpectTest {
|
|||
}
|
||||
|
||||
|
||||
HttpRequest receiveMessage = HttpRequest.builder()
|
||||
public HttpRequest receiveMessage = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
|
@ -86,7 +112,7 @@ public class SQSApiExpectTest extends BaseSQSApiExpectTest {
|
|||
}
|
||||
|
||||
|
||||
HttpRequest receiveMessages = HttpRequest.builder()
|
||||
public HttpRequest receiveMessages = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
|
@ -110,4 +136,113 @@ public class SQSApiExpectTest extends BaseSQSApiExpectTest {
|
|||
apiWhenExist.receiveMessages(URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/"), 10)
|
||||
.toString(), new ReceiveMessageResponseTest().expected().toString());
|
||||
}
|
||||
|
||||
public HttpRequest deleteMessage = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
.addFormParam("Action", "DeleteMessage")
|
||||
.addFormParam("ReceiptHandle", "eXJYhj5rDr9cAe")
|
||||
.addFormParam("Signature", "9%2FkuCc2i78gMsmul%2BRsOPcdQ1OLUKrItqgGIRRBJb8M%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 testDeleteMessageWhenResponseIs2xx() throws Exception {
|
||||
|
||||
HttpResponse deleteMessageResponse = HttpResponse.builder()
|
||||
.statusCode(200)
|
||||
.payload(
|
||||
payloadFromStringWithContentType(
|
||||
"<DeleteMessageResponse><ResponseMetadata><RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId></ResponseMetadata></DeleteMessageResponse>",
|
||||
"text/xml")).build();
|
||||
|
||||
SQSApi apiWhenExist = requestSendsResponse(deleteMessage, deleteMessageResponse);
|
||||
|
||||
apiWhenExist.deleteMessage(URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/"),
|
||||
"eXJYhj5rDr9cAe");
|
||||
}
|
||||
|
||||
public HttpRequest getQueueAttributes = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
.addFormParam("Action", "GetQueueAttributes")
|
||||
.addFormParam("AttributeName.1", "All")
|
||||
.addFormParam("Signature", "welFLn0TV6JlH6s6s60XZTJeJfFXGiXN4qNPrBx7aHc%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 testGetQueueAttributesWhenResponseIs2xx() throws Exception {
|
||||
|
||||
HttpResponse getQueueAttributesResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResourceWithContentType("/attributes.xml", "text/xml")).build();
|
||||
|
||||
SQSApi apiWhenExist = requestSendsResponse(getQueueAttributes, getQueueAttributesResponse);
|
||||
|
||||
assertEquals(apiWhenExist.getQueueAttributes(URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")).toString(), new GetQueueAttributesResponseTest().expected().toString());
|
||||
}
|
||||
|
||||
public HttpRequest getQueueAttributesSubset = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
.addFormParam("Action", "GetQueueAttributes")
|
||||
.addFormParam("AttributeName.1", "VisibilityTimeout")
|
||||
.addFormParam("AttributeName.2", "DelaySeconds")
|
||||
.addFormParam("Signature", "9KaiOOWWyFPTVMOnyHA3ZoXbPBPSD4AZ4q460UNMfDs%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 testGetQueueAttributesSubsetWhenResponseIs2xx() throws Exception {
|
||||
|
||||
HttpResponse getQueueAttributesSubsetResponse = HttpResponse.builder().statusCode(200)
|
||||
.payload(payloadFromResourceWithContentType("/attributes.xml", "text/xml")).build();
|
||||
|
||||
SQSApi apiWhenExist = requestSendsResponse(getQueueAttributesSubset, getQueueAttributesSubsetResponse);
|
||||
|
||||
assertEquals(
|
||||
apiWhenExist.getQueueAttributes(
|
||||
URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/"),
|
||||
ImmutableSet.of("VisibilityTimeout", "DelaySeconds")).toString(),
|
||||
new GetQueueAttributesResponseTest().expected().toString());
|
||||
}
|
||||
|
||||
public HttpRequest setQueueAttribute = HttpRequest.builder()
|
||||
.method("POST")
|
||||
.endpoint("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/")
|
||||
.addHeader("Host", "sqs.us-east-1.amazonaws.com")
|
||||
.addFormParam("Action", "SetQueueAttributes")
|
||||
.addFormParam("Attribute.Name", "MaximumMessageSize")
|
||||
.addFormParam("Attribute.Value", "1")
|
||||
.addFormParam("Signature", "ktBkQ3c%2FrwGcBSec0fkckfo73xmcoTuub5fxudM1qh0%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 testSetQueueAttributeWhenResponseIs2xx() throws Exception {
|
||||
|
||||
HttpResponse setQueueAttributeResponse = HttpResponse.builder()
|
||||
.statusCode(200)
|
||||
.payload(
|
||||
payloadFromStringWithContentType(
|
||||
"<SetQueueAttributesResponse><ResponseMetadata><RequestId>b5293cb5-d306-4a17-9048-b263635abe42</RequestId></ResponseMetadata></SetQueueAttributesResponse>",
|
||||
"text/xml")).build();
|
||||
|
||||
SQSApi apiWhenExist = requestSendsResponse(setQueueAttribute, setQueueAttributeResponse);
|
||||
|
||||
apiWhenExist.setQueueAttribute(URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11/"),
|
||||
"MaximumMessageSize", "1");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,18 +19,17 @@
|
|||
package org.jclouds.sqs;
|
||||
|
||||
import static org.jclouds.sqs.options.ListQueuesOptions.Builder.queuePrefix;
|
||||
import static org.jclouds.sqs.options.ReceiveMessageOptions.Builder.attribute;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import org.jclouds.aws.AWSResponseException;
|
||||
import org.jclouds.sqs.internal.BaseSQSApiLiveTest;
|
||||
import org.jclouds.sqs.options.ReceiveMessageOptions;
|
||||
import org.testng.annotations.AfterTest;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
|
@ -55,7 +54,7 @@ public class SQSApiLiveTest extends BaseSQSApiLiveTest {
|
|||
}
|
||||
|
||||
protected void listQueuesInRegion(String region) throws InterruptedException {
|
||||
SortedSet<URI> allResults = Sets.newTreeSet(context.getApi().listQueuesInRegion(region));
|
||||
SortedSet<URI> allResults = Sets.newTreeSet(api().listQueuesInRegion(region));
|
||||
assertNotNull(allResults);
|
||||
if (allResults.size() >= 1) {
|
||||
URI queue = allResults.last();
|
||||
|
@ -66,35 +65,17 @@ public class SQSApiLiveTest extends BaseSQSApiLiveTest {
|
|||
public static final String PREFIX = System.getProperty("user.name") + "-sqs";
|
||||
|
||||
@Test
|
||||
protected void testCreateQueue() throws InterruptedException {
|
||||
createQueueInRegion(null, PREFIX + "1");
|
||||
protected void testCanRecreateQueueGracefully() throws InterruptedException {
|
||||
recreateQueueInRegion(PREFIX + "1", null);
|
||||
recreateQueueInRegion(PREFIX + "1", null);
|
||||
}
|
||||
|
||||
public String createQueueInRegion(final String region, String queueName) throws InterruptedException {
|
||||
try {
|
||||
Set<URI> result = context.getApi().listQueuesInRegion(region, queuePrefix(queueName));
|
||||
public String recreateQueueInRegion(String queueName, String region) throws InterruptedException {
|
||||
Set<URI> result = api().listQueuesInRegion(region, queuePrefix(queueName));
|
||||
if (result.size() >= 1) {
|
||||
context.getApi().deleteQueue(Iterables.getLast(result));
|
||||
queueName += 1;// cannot recreate a queue within 60 seconds
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
URI queue = null;
|
||||
int tries = 0;
|
||||
while (queue == null && tries < 5) {
|
||||
try {
|
||||
tries++;
|
||||
queue = context.getApi().createQueueInRegion(region, queueName);
|
||||
} catch (AWSResponseException e) {
|
||||
queueName += "1";
|
||||
if (e.getError().getCode().equals("AWS.SimpleQueueService.QueueDeletedRecently"))// TODO
|
||||
// retry
|
||||
// handler
|
||||
continue;
|
||||
throw e;
|
||||
}
|
||||
api().deleteQueue(Iterables.getLast(result));
|
||||
}
|
||||
URI queue = api().createQueueInRegion(region, queueName);
|
||||
assertQueueInList(region, queue);
|
||||
queues.add(queue);
|
||||
return queueName;
|
||||
|
@ -103,35 +84,53 @@ public class SQSApiLiveTest extends BaseSQSApiLiveTest {
|
|||
String message = "hardyharhar";
|
||||
HashCode md5 = Hashing.md5().hashString(message, Charsets.UTF_8);
|
||||
|
||||
@Test(dependsOnMethods = "testCreateQueue")
|
||||
@Test(dependsOnMethods = "testCanRecreateQueueGracefully")
|
||||
protected void testGetQueueAttributes() {
|
||||
for (URI queue : queues) {
|
||||
Map<String, String> attributes = api().getQueueAttributes(queue);
|
||||
assertEquals(api().getQueueAttributes(queue, attributes.keySet()), attributes);
|
||||
}
|
||||
}
|
||||
@Test(dependsOnMethods = "testCanRecreateQueueGracefully")
|
||||
protected void testSetQueueAttribute() {
|
||||
for (URI queue : queues) {
|
||||
api().setQueueAttribute(queue, "MaximumMessageSize", "1024");
|
||||
assertEquals(api().getQueueAttributes(queue).get("MaximumMessageSize"), "1024");
|
||||
}
|
||||
}
|
||||
@Test(dependsOnMethods = "testCanRecreateQueueGracefully")
|
||||
protected void testSendMessage() {
|
||||
for (URI queue : queues) {
|
||||
assertEquals(context.getApi().sendMessage(queue, message).getMD5(), md5);
|
||||
assertEquals(api().sendMessage(queue, message).getMD5(), md5);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testSendMessage")
|
||||
protected void testReceiveMessage() {
|
||||
protected void testReceiveMessageWithoutHidingMessage() {
|
||||
for (URI queue : queues) {
|
||||
assertEquals(context.getApi().receiveMessage(queue, ReceiveMessageOptions.Builder.attribute("All")).getMD5(),
|
||||
md5);
|
||||
assertEquals(api().receiveMessage(queue, attribute("All").visibilityTimeout(0)).getMD5(), md5);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertQueueInList(final String region, URI queue) throws InterruptedException {
|
||||
final URI finalQ = queue;
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
Set<URI> result = context.getApi().listQueuesInRegion(region);
|
||||
assertNotNull(result);
|
||||
assert result.size() >= 1 : result;
|
||||
assertTrue(result.contains(finalQ), finalQ + " not in " + result);
|
||||
@Test(dependsOnMethods = "testReceiveMessageWithoutHidingMessage")
|
||||
protected void testDeleteMessage() throws InterruptedException {
|
||||
for (URI queue : queues) {
|
||||
String receiptHandle = api().receiveMessage(queue, attribute("None").visibilityTimeout(0)).getReceiptHandle();
|
||||
api().deleteMessage(queue, receiptHandle);
|
||||
assertNoMessages(queue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
public void shutdown() {
|
||||
context.close();
|
||||
@Override
|
||||
@AfterClass(groups = "live")
|
||||
protected void tearDownContext() {
|
||||
for (URI queue : queues) {
|
||||
api().deleteQueue(queue);
|
||||
}
|
||||
super.tearDownContext();
|
||||
}
|
||||
|
||||
protected SQSApi api() {
|
||||
return context.getApi();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.handlers;
|
||||
|
||||
import static org.easymock.EasyMock.createMock;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.aws.domain.AWSError;
|
||||
import org.jclouds.aws.util.AWSUtils;
|
||||
import org.jclouds.http.HttpCommand;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Tests behavior of {@code SQSErrorRetryHandler}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "SQSErrorRetryHandlerTest")
|
||||
public class SQSErrorRetryHandlerTest {
|
||||
|
||||
String code = "AWS.SimpleQueueService.QueueDeletedRecently";
|
||||
AWSError error;
|
||||
HttpResponse response = HttpResponse.builder().statusCode(400)
|
||||
.payload(String.format("<Error><Code>%s</Code></Error>", code)).build();
|
||||
|
||||
public SQSErrorRetryHandlerTest() {
|
||||
error = new AWSError();
|
||||
error.setCode(code);
|
||||
}
|
||||
|
||||
public void testQueueDeletedRecentlyRetriesWhen59SleepsAndTries() {
|
||||
|
||||
SQSErrorRetryHandler retry = new SQSErrorRetryHandler(createMock(AWSUtils.class),
|
||||
createMock(BackoffLimitedRetryHandler.class), ImmutableSet.<String> of(), 60, 100);
|
||||
|
||||
HttpCommand command = createHttpCommandForFailureCount(59);
|
||||
|
||||
Stopwatch watch = new Stopwatch().start();
|
||||
assertTrue(retry.shouldRetryRequestOnError(command, response, error));
|
||||
assertEquals(command.getFailureCount(), 60);
|
||||
assertTrue(watch.stop().elapsedTime(TimeUnit.MILLISECONDS) >= 100);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testQueueDeletedRecentlyRetriesWhen60DoesntTry() {
|
||||
|
||||
SQSErrorRetryHandler retry = new SQSErrorRetryHandler(createMock(AWSUtils.class),
|
||||
createMock(BackoffLimitedRetryHandler.class), ImmutableSet.<String> of(), 60, 100);
|
||||
|
||||
HttpCommand command = createHttpCommandForFailureCount(60);
|
||||
|
||||
Stopwatch watch = new Stopwatch().start();
|
||||
assertFalse(retry.shouldRetryRequestOnError(command, response, error));
|
||||
assertEquals(command.getFailureCount(), 61);
|
||||
assertTrue(watch.stop().elapsedTime(TimeUnit.MILLISECONDS) < 100);
|
||||
}
|
||||
|
||||
//TODO: make a builder for this
|
||||
HttpCommand createHttpCommandForFailureCount(final int failureCount) {
|
||||
return new HttpCommand() {
|
||||
int fCount = failureCount;
|
||||
|
||||
@Override
|
||||
public int incrementRedirectCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRedirectCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReplayable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int incrementFailureCount() {
|
||||
return ++fCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFailureCount() {
|
||||
return fCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpRequest getCurrentRequest() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentRequest(HttpRequest request) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setException(Exception exception) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception getException() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -18,11 +18,19 @@
|
|||
*/
|
||||
package org.jclouds.sqs.internal;
|
||||
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jclouds.apis.BaseContextLiveTest;
|
||||
import org.jclouds.rest.RestContext;
|
||||
import org.jclouds.sqs.SQSApi;
|
||||
import org.jclouds.sqs.SQSApiMetadata;
|
||||
import org.jclouds.sqs.SQSAsyncApi;
|
||||
import org.jclouds.sqs.domain.Message;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
@ -43,6 +51,31 @@ public class BaseSQSApiLiveTest extends BaseContextLiveTest<RestContext<SQSApi,
|
|||
return SQSApiMetadata.CONTEXT_TOKEN;
|
||||
}
|
||||
|
||||
protected void assertNoMessages(final URI queue) throws InterruptedException {
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
Message message = api().receiveMessage(queue);
|
||||
assertNull(message, "message: " + message + " left in queue " + queue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void assertQueueInList(final String region, URI queue) throws InterruptedException {
|
||||
final URI finalQ = queue;
|
||||
assertEventually(new Runnable() {
|
||||
public void run() {
|
||||
Set<URI> result = api().listQueuesInRegion(region);
|
||||
assertNotNull(result);
|
||||
assert result.size() >= 1 : result;
|
||||
assertTrue(result.contains(finalQ), finalQ + " not in " + result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SQSApi api() {
|
||||
return context.getApi();
|
||||
}
|
||||
|
||||
private static final int INCONSISTENCY_WINDOW = 10000;
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.parse;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
||||
import org.jclouds.http.HttpResponse;
|
||||
import org.jclouds.http.functions.ReturnStringIf2xx;
|
||||
import org.jclouds.sqs.xml.RegexQueueHandler;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during
|
||||
// surefire
|
||||
@Test(groups = "unit", testName = "CreateQueueResponseTest")
|
||||
public class CreateQueueResponseTest {
|
||||
|
||||
public void test() {
|
||||
InputStream is = getClass().getResourceAsStream("/create_queue.xml");
|
||||
|
||||
URI expected = expected();
|
||||
|
||||
RegexQueueHandler handler = new RegexQueueHandler(new ReturnStringIf2xx());
|
||||
URI result = handler.apply(HttpResponse.builder().statusCode(200).payload(is).build());
|
||||
|
||||
assertEquals(result.toString(), expected.toString());
|
||||
|
||||
}
|
||||
|
||||
public URI expected() {
|
||||
return URI.create("https://sqs.us-east-1.amazonaws.com/993194456877/adrian-sqs11");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.sqs.parse;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.http.functions.BaseHandlerTest;
|
||||
import org.jclouds.sqs.xml.AttributesHandler;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
// NOTE:without testName, this will not call @Before* and fail w/NPE during
|
||||
// surefire
|
||||
@Test(groups = "unit", testName = "GetQueueAttributesResponseTest")
|
||||
public class GetQueueAttributesResponseTest extends BaseHandlerTest {
|
||||
|
||||
public void test() {
|
||||
InputStream is = getClass().getResourceAsStream("/attributes.xml");
|
||||
|
||||
Map<String, String> expected = expected();
|
||||
|
||||
AttributesHandler handler = injector.getInstance(AttributesHandler.class);
|
||||
Map<String, String> result = factory.create(handler).parse(is);
|
||||
|
||||
assertEquals(result.toString(), expected.toString());
|
||||
|
||||
}
|
||||
|
||||
public Map<String, String> expected() {
|
||||
return ImmutableMap.<String, String>builder()
|
||||
.put("VisibilityTimeout", "30")
|
||||
.put("DelaySeconds", "0")
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -57,9 +57,7 @@ public class ReceiveMessageResponseTest extends BaseHandlerTest {
|
|||
.builder()
|
||||
.id("5fea7756-0ea4-451a-a703-a558b933e274")
|
||||
.receiptHandle(
|
||||
"MbZj6wDWli+JvwwJaBV+3dcjk2YW2vA3+STFFljTM8tJJg6HRG6PYSasuWXPJB+Cw" + "\n"
|
||||
+ " Lj1FjgXUv1uSj1gUPAWV66FU/WeR4mq2OKpEGYWbnLmpRCJVAyeMjeU5ZBdtcQ+QE" + "\n"
|
||||
+ " auMZc8ZRv37sIW2iJKq3M9MFx1YvV11A2x/KSbkJ0=")
|
||||
"+eXJYhj5rDr9cAe/9BuheT5fysi9BoqtEZSkO7IazVbNHg60eCCINxLqaSVv2pFHrWeWNpZwbleSkWRbCtZaQGgpOx/3cWJZiNSG1KKlJX4IOwISFvb3FwByMx4w0lnINeXzcw2VcKQXNrCatO9gdIiVPvJC3SCKatYM/7YTidtjqc8igrtYW2E2mHlCy3NXPCeXxP4tSvyEwIxpDAmMT7IF0mWvTHS6+JBUtFUsrmi61oIHlESNrD1OjdB1QQw+kdvJ6VbsntbJNNYKw+YqdqWNpZkiGQ8y1z9OdHsr1+4=")
|
||||
.md5(HashCodes.fromBytes(CryptoStreams.hex("fafb00f5732ab283681e124bf8747ed1")))
|
||||
.body("This is a test message")
|
||||
.addAttribute("SenderId", "195004372649")
|
||||
|
|
|
@ -52,9 +52,7 @@ public class SendMessageResponseTest {
|
|||
}
|
||||
|
||||
public MessageIdAndMD5 expected() {
|
||||
return MessageIdAndMD5.builder()
|
||||
.id("c332b2b0-b61f-42d3-8832-d03ebd89f68d")
|
||||
.md5(HashCodes.fromBytes(CryptoStreams.hex("e32aedf2b2b25355d04b1507055532e6")))
|
||||
.build();
|
||||
return MessageIdAndMD5.builder().id("c332b2b0-b61f-42d3-8832-d03ebd89f68d")
|
||||
.md5(HashCodes.fromBytes(CryptoStreams.hex("e32aedf2b2b25355d04b1507055532e6"))).build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<GetQueueAttributesResponse>
|
||||
<GetQueueAttributesResult>
|
||||
<Attribute>
|
||||
<Name>VisibilityTimeout</Name>
|
||||
<Value>30</Value>
|
||||
</Attribute>
|
||||
<Attribute>
|
||||
<Name>DelaySeconds</Name>
|
||||
<Value>0</Value>
|
||||
</Attribute>
|
||||
</GetQueueAttributesResult>
|
||||
</GetQueueAttributesResponse>
|
|
@ -4,11 +4,7 @@
|
|||
<MessageId>
|
||||
5fea7756-0ea4-451a-a703-a558b933e274
|
||||
</MessageId>
|
||||
<ReceiptHandle>
|
||||
MbZj6wDWli+JvwwJaBV+3dcjk2YW2vA3+STFFljTM8tJJg6HRG6PYSasuWXPJB+Cw
|
||||
Lj1FjgXUv1uSj1gUPAWV66FU/WeR4mq2OKpEGYWbnLmpRCJVAyeMjeU5ZBdtcQ+QE
|
||||
auMZc8ZRv37sIW2iJKq3M9MFx1YvV11A2x/KSbkJ0=
|
||||
</ReceiptHandle>
|
||||
<ReceiptHandle>+eXJYhj5rDr9cAe/9BuheT5fysi9BoqtEZSkO7IazVbNHg60eCCINxLqaSVv2pFHrWeWNpZwbleSkWRbCtZaQGgpOx/3cWJZiNSG1KKlJX4IOwISFvb3FwByMx4w0lnINeXzcw2VcKQXNrCatO9gdIiVPvJC3SCKatYM/7YTidtjqc8igrtYW2E2mHlCy3NXPCeXxP4tSvyEwIxpDAmMT7IF0mWvTHS6+JBUtFUsrmi61oIHlESNrD1OjdB1QQw+kdvJ6VbsntbJNNYKw+YqdqWNpZkiGQ8y1z9OdHsr1+4=</ReceiptHandle>
|
||||
<MD5OfBody>
|
||||
fafb00f5732ab283681e124bf8747ed1
|
||||
</MD5OfBody>
|
||||
|
|
Loading…
Reference in New Issue