initial cut of azure queue service

git-svn-id: http://jclouds.googlecode.com/svn/trunk@1883 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
adrian.f.cole 2009-09-03 17:55:57 +00:00
parent 6a8c3d160c
commit 64cf29701d
16 changed files with 1012 additions and 0 deletions

View File

@ -0,0 +1,123 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.azure.storage.queue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.azure.storage.domain.MetadataList;
import org.jclouds.azure.storage.filters.SharedKeyAuthentication;
import org.jclouds.azure.storage.options.CreateOptions;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
import org.jclouds.azure.storage.queue.xml.AccountNameEnumerationResultsHandler;
import org.jclouds.azure.storage.reference.AzureStorageHeaders;
import org.jclouds.rest.Header;
import org.jclouds.rest.Query;
import org.jclouds.rest.RequestFilters;
import org.jclouds.rest.SkipEncoding;
import org.jclouds.rest.XMLResponseParser;
/**
* Provides access to Azure Queue via their REST API.
* <p/>
* The Queue service stores messages that may be read by any client who has access to the storage
* account.
* <p/>
* A queue can contain an unlimited number of messages, each of which can be up to 8 KB in size.
* Messages are generally added to the end of the queue and retrieved from the front of the queue,
* although first in, first out (FIFO) behavior is not guaranteed.
* <p/>
* If you need to store messages larger than 8 KB, you can store message data as a blob or in a
* table, and then store a reference to the data as a message in a queue.
* <p/>
* All commands return a Future of the result from Azure Queue. Any exceptions incurred during
* processing will be wrapped in an {@link ExecutionException} as documented in {@link Future#get()}.
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
* @author Adrian Cole
*/
@SkipEncoding('/')
@RequestFilters(SharedKeyAuthentication.class)
@Header(key = AzureStorageHeaders.VERSION, value = "2009-07-17")
public interface AzureQueueConnection {
/**
* The List Queues operation returns a list of the queues under the specified account.
* <p />
* The 2009-07-17 version of the List Queues operation times out after 30 seconds.
*
* @param listOptions
* controls the number or type of results requested
* @see ListOptions
*/
@GET
@XMLResponseParser(AccountNameEnumerationResultsHandler.class)
@Path("/")
@Query(key = "comp", value = "list")
MetadataList<QueueMetadata> listQueues(ListOptions... listOptions);
/**
* The Create Queue operation creates a new queue under the specified account.
* <p/>
* You can specify user-defined metadata as name-value pairs on the queue at the time that it is
* created.
* <p/>
* When a queue with the specified name already exists, the Queue service checks the metadata
* associated with the existing queue. If the existing metadata is identical to the metadata
* specified on the Create Queue request, status code 204 (No Content) is returned.
* <p/>
* If the existing metadata does not match the metadata provided with the Create Queue request,
* the operation fails and status code 409 (Conflict) is returned. Clients can take advantage of
* this behavior to avoid an additional call to check whether a named queue already exists.
*
* @see CreateQueueOptions
*
*/
@PUT
@Path("{queue}")
@Query(key = "restype", value = "queue")
boolean createQueue(@PathParam("queue") String queue, CreateOptions... options);
/**
* The Delete Queue operation permanently deletes the specified queue.
*
* <p/>
* When a queue is successfully deleted, the queue is immediately marked for deletion and is no
* longer accessible to clients. The queue is later removed from the Queue service during garbage
* collection.
*
*/
@DELETE
@Path("{queue}")
@Query(key = "restype", value = "queue")
boolean deleteQueue(@PathParam("queue") String queue);
}

View File

@ -0,0 +1,16 @@
package org.jclouds.azure.storage.queue;
import org.jclouds.cloud.CloudContext;
/**
* Represents an authenticated context to Azure Queue Service.
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd135733.aspx" />
* @see AzureQueueConnection
* @see CloudContext
* @author Adrian Cole
*
*/
public interface AzureQueueContext extends CloudContext<AzureQueueConnection> {
}

View File

@ -0,0 +1,114 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.azure.storage.queue;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_ADDRESS;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_MAX_REDIRECTS;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_MAX_RETRIES;
import static org.jclouds.http.HttpConstants.PROPERTY_HTTP_SECURE;
import static org.jclouds.http.HttpConstants.PROPERTY_SAX_DEBUG;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_IO_WORKER_THREADS;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTIONS;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_CONNECTION_REUSE;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_MAX_SESSION_FAILURES;
import static org.jclouds.http.pool.PoolConstants.PROPERTY_POOL_REQUEST_INVOKER_THREADS;
import java.util.List;
import java.util.Properties;
import org.jclouds.azure.storage.queue.config.AzureQueueContextModule;
import org.jclouds.azure.storage.queue.config.RestAzureQueueConnectionModule;
import org.jclouds.azure.storage.reference.AzureStorageConstants;
import org.jclouds.azure.storage.xml.config.AzureStorageParserModule;
import org.jclouds.cloud.CloudContextBuilder;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Creates {@link AzureQueueContext} or {@link Injector} instances based on the most commonly
* requested arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole
* @see AzureQueueContext
*/
public class AzureQueueContextBuilder extends
CloudContextBuilder<AzureQueueConnection, AzureQueueContext> {
public AzureQueueContextBuilder(Properties props) {
super(props);
}
public static AzureQueueContextBuilder newBuilder(String id, String secret) {
Properties properties = new Properties();
properties.setProperty(PROPERTY_HTTP_ADDRESS, id + ".queue.core.windows.net");
properties.setProperty(PROPERTY_HTTP_SECURE, "true");
properties.setProperty(PROPERTY_SAX_DEBUG, "false");
properties.setProperty(PROPERTY_HTTP_MAX_RETRIES, "5");
properties.setProperty(PROPERTY_HTTP_MAX_REDIRECTS, "5");
properties.setProperty(PROPERTY_POOL_MAX_CONNECTION_REUSE, "75");
properties.setProperty(PROPERTY_POOL_MAX_SESSION_FAILURES, "2");
properties.setProperty(PROPERTY_POOL_REQUEST_INVOKER_THREADS, "1");
properties.setProperty(PROPERTY_POOL_IO_WORKER_THREADS, "2");
properties.setProperty(PROPERTY_POOL_MAX_CONNECTIONS, "12");
AzureQueueContextBuilder builder = new AzureQueueContextBuilder(properties);
builder.authenticate(id, secret);
return builder;
}
public void authenticate(String id, String secret) {
properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT, checkNotNull(id,
"azureStorageAccount"));
properties.setProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY, checkNotNull(secret,
"azureStorageKey"));
}
public AzureQueueContext buildContext() {
return buildInjector().getInstance(AzureQueueContext.class);
}
protected void addParserModule(List<Module> modules) {
modules.add(new AzureStorageParserModule());
}
protected void addContextModule(List<Module> modules) {
modules.add(new AzureQueueContextModule());
}
protected void addConnectionModule(List<Module> modules) {
modules.add(new RestAzureQueueConnectionModule());
}
}

View File

@ -0,0 +1,22 @@
package org.jclouds.azure.storage.queue.config;
import org.jclouds.azure.storage.queue.AzureQueueConnection;
import org.jclouds.azure.storage.queue.AzureQueueContext;
import org.jclouds.azure.storage.queue.internal.GuiceAzureQueueContext;
import com.google.inject.AbstractModule;
/**
* Configures the {@link AzureQueueContext}; requires {@link AzureQueueConnection} bound.
*
* @author Adrian Cole
*/
public class AzureQueueContextModule extends AbstractModule {
@Override
protected void configure() {
this.requireBinding(AzureQueueConnection.class);
bind(AzureQueueContext.class).to(GuiceAzureQueueContext.class);
}
}

View File

@ -0,0 +1,29 @@
package org.jclouds.azure.storage.queue.config;
import java.net.URI;
import org.jclouds.azure.storage.queue.AzureQueueConnection;
import org.jclouds.azure.storage.config.RestAzureStorageConnectionModule;
import org.jclouds.cloud.ConfiguresCloudConnection;
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.RestClientFactory;
import com.google.inject.Provides;
import com.google.inject.Singleton;
/**
* Configures the Azure Queue Service connection, including logging and http transport.
*
* @author Adrian Cole
*/
@ConfiguresCloudConnection
@RequiresHttp
public class RestAzureQueueConnectionModule extends RestAzureStorageConnectionModule {
@Provides
@Singleton
protected AzureQueueConnection provideAzureStorageConnection(URI uri, RestClientFactory factory) {
return factory.create(uri, AzureQueueConnection.class);
}
}

View File

@ -0,0 +1,86 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.azure.storage.queue.domain;
import java.net.URI;
/**
*
* @author Adrian Cole
*
*/
public class QueueMetadata {
private final String name;
private final URI url;
public QueueMetadata(String name, URI url) {
this.name = name;
this.url = url;
}
@Override
public String toString() {
return "QueueMetadata [name=" + name + ", url=" + url + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((url == null) ? 0 : url.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
QueueMetadata other = (QueueMetadata) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (url == null) {
if (other.url != null)
return false;
} else if (!url.equals(other.url))
return false;
return true;
}
public String getName() {
return name;
}
public URI getUrl() {
return url;
}
}

View File

@ -0,0 +1,55 @@
package org.jclouds.azure.storage.queue.internal;
import java.io.IOException;
import javax.annotation.Resource;
import org.jclouds.azure.storage.queue.AzureQueueConnection;
import org.jclouds.azure.storage.queue.AzureQueueContext;
import org.jclouds.lifecycle.Closer;
import org.jclouds.logging.Logger;
import com.google.inject.Inject;
import com.google.inject.Injector;
/**
* Uses a Guice Injector to configure the objects served by AzureQueueContext methods.
*
* @author Adrian Cole
* @see Injector
*/
public class GuiceAzureQueueContext implements AzureQueueContext {
@Resource
private Logger logger = Logger.NULL;
private final Injector injector;
private final Closer closer;
@Inject
private GuiceAzureQueueContext(Injector injector, Closer closer) {
this.injector = injector;
this.closer = closer;
}
/**
* {@inheritDoc}
*/
public AzureQueueConnection getConnection() {
return injector.getInstance(AzureQueueConnection.class);
}
/**
* {@inheritDoc}
*
* @see Closer
*/
public void close() {
try {
closer.close();
} catch (IOException e) {
logger.error(e, "error closing content");
}
}
}

View File

@ -0,0 +1,92 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.azure.storage.queue.xml;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.jclouds.azure.storage.domain.MetadataList;
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
import org.jclouds.http.functions.ParseSax;
import com.google.inject.Inject;
/**
* Parses the following XML document:
* <p/>
* EnumerationResults AccountName="http://myaccount.queue.core.windows.net"
*
* @see <a href="http://msdn.microsoft.com/en-us/library/dd179352.aspx" />
* @author Adrian Cole
*/
public class AccountNameEnumerationResultsHandler extends
ParseSax.HandlerWithResult<MetadataList<QueueMetadata>> {
private List<QueueMetadata> metadata = new ArrayList<QueueMetadata>();
private String prefix;
private String marker;
private int maxResults;
private String nextMarker;
private String currentName;
private URI currentUrl;
private StringBuilder currentText = new StringBuilder();
@Inject
public AccountNameEnumerationResultsHandler() {
}
public MetadataList<QueueMetadata> getResult() {
return new MetadataList<QueueMetadata>(prefix, marker, maxResults, metadata, nextMarker);
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("MaxResults")) {
maxResults = Integer.parseInt(currentText.toString().trim());
} else if (qName.equals("Marker")) {
marker = currentText.toString().trim();
marker = (marker.equals("")) ? null : marker;
} else if (qName.equals("Prefix")) {
prefix = currentText.toString().trim();
prefix = (prefix.equals("")) ? null : prefix;
} else if (qName.equals("NextMarker")) {
nextMarker = currentText.toString().trim();
nextMarker = (nextMarker.equals("")) ? null : nextMarker;
} else if (qName.equals("Queue")) {
metadata.add(new QueueMetadata(currentName, currentUrl));
currentUrl = null;
currentName = null;
} else if (qName.equals("Url")) {
currentUrl = URI.create(currentText.toString().trim());
} else if (qName.equals("QueueName")) {
currentName = currentText.toString().trim();
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -0,0 +1,29 @@
package org.jclouds.azure.storage.queue.xml;
import org.jclouds.azure.storage.domain.MetadataList;
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
import org.jclouds.azure.storage.xml.AzureStorageParserFactory;
import org.jclouds.http.functions.ParseSax;
import com.google.inject.Inject;
import com.google.inject.Provider;
/**
* Creates Parsers needed to interpret Azure Queue Service messages. This class uses guice assisted
* inject, which mandates the creation of many single-method interfaces. These interfaces are not
* intended for public api.
*
* @author Adrian Cole
*/
public class AzureQueueParserFactory extends AzureStorageParserFactory {
@Inject
private GenericParseFactory<MetadataList<QueueMetadata>> parseContainerMetadataListFactory;
@Inject
Provider<AccountNameEnumerationResultsHandler> containerMetaListHandlerProvider;
public ParseSax<MetadataList<QueueMetadata>> createContainerMetadataListParser() {
return parseContainerMetadataListFactory.create(containerMetaListHandlerProvider.get());
}
}

View File

@ -0,0 +1,40 @@
package org.jclouds.azure.storage.queue.xml.config;
import org.jclouds.azure.storage.domain.MetadataList;
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
import org.jclouds.azure.storage.queue.xml.AccountNameEnumerationResultsHandler;
import org.jclouds.azure.storage.xml.AzureStorageParserFactory;
import org.jclouds.azure.storage.xml.config.AzureStorageParserModule;
import org.jclouds.command.ConfiguresResponseTransformer;
import org.jclouds.http.functions.ParseSax;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryProvider;
/**
* Creates the factories needed to interpret Azure Queue Service responses
*
* @author Adrian Cole
*/
@ConfiguresResponseTransformer
public class AzureQueueParserModule extends AzureStorageParserModule {
protected final TypeLiteral<AzureStorageParserFactory.GenericParseFactory<MetadataList<QueueMetadata>>> accountNameEnumerationResultsHandler = new TypeLiteral<AzureStorageParserFactory.GenericParseFactory<MetadataList<QueueMetadata>>>() {
};
@Override
protected void bindParserImplementationsToReturnTypes() {
super.bindParserImplementationsToReturnTypes();
bind(new TypeLiteral<ParseSax.HandlerWithResult<MetadataList<QueueMetadata>>>() {
}).to(AccountNameEnumerationResultsHandler.class);
}
@Override
protected void bindCallablesThatReturnParseResults() {
super.bindCallablesThatReturnParseResults();
bind(accountNameEnumerationResultsHandler).toProvider(
FactoryProvider.newFactory(accountNameEnumerationResultsHandler,
new TypeLiteral<ParseSax<MetadataList<QueueMetadata>>>() {
}));
}
}

View File

@ -0,0 +1,98 @@
package org.jclouds.azure.storage.queue;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.SecureRandom;
import org.jclouds.azure.storage.domain.MetadataList;
import org.jclouds.azure.storage.options.CreateOptions;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
import org.jclouds.azure.storage.reference.AzureStorageConstants;
import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.Injector;
/**
* Tests behavior of {@code AzureQueueConnection}
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true, testName = "cloudservers.AzureQueueConnectionLiveTest")
public class AzureQueueConnectionLiveTest {
protected static final String sysAzureStorageAccount = System
.getProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT);
protected static final String sysAzureStorageKey = System
.getProperty(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY);
protected AzureQueueConnection connection;
private String queuePrefix = System.getProperty("user.name") + "-azurequeue";
@BeforeGroups(groups = { "live" })
public void setupConnection() {
Injector injector = AzureQueueContextBuilder.newBuilder(sysAzureStorageAccount,
sysAzureStorageKey).withModules(new Log4JLoggingModule()).withSaxDebug()
.buildInjector();
connection = injector.getInstance(AzureQueueConnection.class);
}
@Test
public void testListQueues() throws Exception {
MetadataList<QueueMetadata> response = connection.listQueues();
assert null != response;
long initialQueueCount = response.getMetadata().size();
assertTrue(initialQueueCount >= 0);
}
String privateQueue;
@Test(timeOut = 5 * 60 * 1000)
public void testCreateQueue() throws Exception {
boolean created = false;
while (!created) {
privateQueue = queuePrefix + new SecureRandom().nextInt();
try {
created = connection.createQueue(privateQueue, CreateOptions.Builder
.withMetadata(ImmutableMultimap.of("foo", "bar")));
} catch (UndeclaredThrowableException e) {
HttpResponseException htpe = (HttpResponseException) e.getCause().getCause();
if (htpe.getResponse().getStatusCode() == 409)
continue;
throw e;
}
}
MetadataList<QueueMetadata> response = connection.listQueues();
assert null != response;
long queueCount = response.getMetadata().size();
assertTrue(queueCount >= 1);
// TODO ... check to see the queue actually exists
}
@Test
public void testListQueuesWithOptions() throws Exception {
MetadataList<QueueMetadata> response = connection.listQueues(ListOptions.Builder.prefix(
privateQueue).maxResults(1));
assert null != response;
long initialQueueCount = response.getMetadata().size();
assertTrue(initialQueueCount >= 0);
assertEquals(privateQueue, response.getPrefix());
assertEquals(1, response.getMaxResults());
}
@Test(timeOut = 5 * 60 * 1000, dependsOnMethods = { "testCreateQueue" })
public void testDeleteQueue() throws Exception {
assert connection.deleteQueue(privateQueue);
// TODO loop for up to 30 seconds checking if they are really gone
}
}

View File

@ -0,0 +1,161 @@
package org.jclouds.azure.storage.queue;
import static org.jclouds.azure.storage.options.CreateOptions.Builder.withMetadata;
import static org.jclouds.azure.storage.options.ListOptions.Builder.maxResults;
import static org.testng.Assert.assertEquals;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collections;
import javax.ws.rs.HttpMethod;
import org.jclouds.azure.storage.options.CreateOptions;
import org.jclouds.azure.storage.options.ListOptions;
import org.jclouds.azure.storage.queue.xml.config.AzureQueueParserModule;
import org.jclouds.azure.storage.reference.AzureStorageConstants;
import org.jclouds.concurrent.WithinThreadExecutorService;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.rest.JaxrsAnnotationProcessor;
import org.jclouds.rest.config.JaxrsModule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMultimap;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.name.Names;
/**
* Tests behavior of {@code AzureQueueConnection}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "cloudservers.AzureQueueConnectionTest")
public class AzureQueueConnectionTest {
JaxrsAnnotationProcessor.Factory factory;
private static final Class<? extends ListOptions[]> listOptionsVarargsClass = new ListOptions[] {}
.getClass();
private static final Class<? extends CreateOptions[]> createOptionsVarargsClass = new CreateOptions[] {}
.getClass();
public void testListQueues() throws SecurityException, NoSuchMethodException {
Method method = AzureQueueConnection.class.getMethod("listQueues", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] {});
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/");
assertEquals(httpMethod.getEndpoint().getQuery(), "comp=list");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
.singletonList("2009-07-17"));
assertEquals(processor.createResponseParser(method).getClass(), ParseSax.class);
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testListQueuesOptions() throws SecurityException, NoSuchMethodException {
Method method = AzureQueueConnection.class.getMethod("listQueues", listOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { maxResults(
1).marker("marker").prefix("prefix") });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/");
assertEquals(httpMethod.getEndpoint().getQuery(),
"comp=list&marker=marker&maxresults=1&prefix=prefix");
assertEquals(httpMethod.getMethod(), HttpMethod.GET);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
.singletonList("2009-07-17"));
assertEquals(processor.createResponseParser(method).getClass(), ParseSax.class);
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testCreateQueue() throws SecurityException, NoSuchMethodException {
Method method = AzureQueueConnection.class.getMethod("createQueue", String.class,
createOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "queue" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/queue");
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=queue");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 2);
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
.singletonList("2009-07-17"));
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testDeleteQueue() throws SecurityException, NoSuchMethodException {
Method method = AzureQueueConnection.class.getMethod("deleteQueue", String.class);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "queue" });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/queue");
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=queue");
assertEquals(httpMethod.getMethod(), HttpMethod.DELETE);
assertEquals(httpMethod.getHeaders().size(), 1);
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
.singletonList("2009-07-17"));
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
public void testCreateQueueOptions() throws SecurityException, NoSuchMethodException {
Method method = AzureQueueConnection.class.getMethod("createQueue", String.class,
createOptionsVarargsClass);
URI endpoint = URI.create("http://localhost");
HttpRequest httpMethod = processor.createRequest(endpoint, method, new Object[] { "queue",
withMetadata(ImmutableMultimap.of("foo", "bar")) });
assertEquals(httpMethod.getEndpoint().getHost(), "localhost");
assertEquals(httpMethod.getEndpoint().getPath(), "/queue");
assertEquals(httpMethod.getEndpoint().getQuery(), "restype=queue");
assertEquals(httpMethod.getMethod(), HttpMethod.PUT);
assertEquals(httpMethod.getHeaders().size(), 3);
assertEquals(httpMethod.getHeaders().get("x-ms-version"), Collections
.singletonList("2009-07-17"));
assertEquals(httpMethod.getHeaders().get("x-ms-meta-foo"), Collections.singletonList("bar"));
assertEquals(httpMethod.getHeaders().get("Content-Length"), Collections.singletonList("0"));
assertEquals(processor.createResponseParser(method).getClass(), ReturnTrueIf2xx.class);
// TODO check generic type of response parser
assertEquals(processor.createExceptionParserOrNullIfNotFound(method), null);
}
JaxrsAnnotationProcessor processor;
@BeforeClass
void setupFactory() {
factory = Guice.createInjector(
new AzureQueueParserModule(),
new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).toInstance(URI.create("http://localhost:8080"));
bindConstant().annotatedWith(
Names.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_ACCOUNT)).to(
"user");
bindConstant().annotatedWith(
Names.named(AzureStorageConstants.PROPERTY_AZURESTORAGE_KEY)).to(
HttpUtils.toBase64String("key".getBytes()));
}
}, new JaxrsModule(), new ExecutorServiceModule(new WithinThreadExecutorService()),
new JavaUrlHttpCommandExecutorServiceModule()).getInstance(
JaxrsAnnotationProcessor.Factory.class);
processor = factory.create(AzureQueueConnection.class);
}
}

View File

@ -0,0 +1,75 @@
/**
*
* Copyright (C) 2009 Global Cloud Specialists, Inc. <info@globalcloudspecialists.com>
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.azure.storage.queue.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import java.net.URI;
import org.jclouds.azure.storage.domain.MetadataList;
import org.jclouds.azure.storage.queue.domain.QueueMetadata;
import org.jclouds.http.functions.ParseSax;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
/**
* Tests behavior of {@code ParseFlavorListFromGsonResponseTest}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "azurequeue.AccountNameEnumerationResultsHandlerTest")
public class AccountNameEnumerationResultsHandlerTest extends BaseHandlerTest {
public void testApplyInputStream() {
InputStream is = getClass().getResourceAsStream("/test_list_queues.xml");
MetadataList<QueueMetadata> list = new MetadataList<QueueMetadata>("q", null, 3,
ImmutableList.of(new QueueMetadata("q1", URI
.create("http://myaccount.queue.core.windows.net/q1")), new QueueMetadata(
"q2", URI.create("http://myaccount.queue.core.windows.net/q2")),
new QueueMetadata("q3", URI
.create("http://myaccount.queue.core.windows.net/q3")))
, "q4");
ParseSax<MetadataList<QueueMetadata>> parser = parserFactory
.createContainerMetadataListParser();
MetadataList<QueueMetadata> result = parser.parse(is);
assertEquals(result, list);
}
public void testApplyInputStreamWithOptions() {
InputStream is = getClass().getResourceAsStream("/test_list_queues_options.xml");
MetadataList<QueueMetadata> list = new MetadataList<QueueMetadata>("q", "q4", 3,
ImmutableList.of(new QueueMetadata("q4", URI
.create("http://myaccount.queue.core.windows.net/q4")), new QueueMetadata(
"q5", URI.create("http://myaccount.queue.core.windows.net/q5")))
, null);
ParseSax<MetadataList<QueueMetadata>> parser = parserFactory
.createContainerMetadataListParser();
MetadataList<QueueMetadata> result = parser.parse(is);
assertEquals(result, list);
}
}

View File

@ -0,0 +1,35 @@
package org.jclouds.azure.storage.queue.xml;
import org.jclouds.azure.storage.queue.xml.AzureQueueParserFactory;
import org.jclouds.azure.storage.queue.xml.config.AzureQueueParserModule;
import org.jclouds.http.functions.config.ParserModule;
import org.jclouds.util.DateService;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import com.google.inject.Guice;
import com.google.inject.Injector;
public class BaseHandlerTest {
protected AzureQueueParserFactory parserFactory = null;
protected DateService dateService = null;
private Injector injector;
@BeforeTest
protected void setUpInjector() {
injector = Guice.createInjector(new AzureQueueParserModule(), new ParserModule());
parserFactory = injector.getInstance(AzureQueueParserFactory.class);
dateService = injector.getInstance(DateService.class);
assert parserFactory != null;
}
@AfterTest
protected void tearDownInjector() {
parserFactory = null;
dateService = null;
injector = null;
}
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults AccountName="http://myaccount.queue.core.windows.net">
<Prefix>q</Prefix>
<MaxResults>3</MaxResults>
<Queues>
<Queue>
<QueueName>q1</QueueName>
<Url>http://myaccount.queue.core.windows.net/q1</Url>
</Queue>
<Queue>
<QueueName>q2</QueueName>
<Url>http://myaccount.queue.core.windows.net/q2</Url>
</Queue>
<Queue>
<QueueName>q3</QueueName>
<Url>http://myaccount.queue.core.windows.net/q3</Url>
</Queue>
</Queues>
<NextMarker>q4</NextMarker>
</EnumerationResults>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults AccountName="http://myaccount.queue.core.windows.net">
<Prefix>q</Prefix>
<Marker>q4</Marker>
<MaxResults>3</MaxResults>
<Queues>
<Queue>
<QueueName>q4</QueueName>
<Url>http://myaccount.queue.core.windows.net/q4</Url>
</Queue>
<Queue>
<QueueName>q5</QueueName>
<Url>http://myaccount.queue.core.windows.net/q5</Url>
</Queue>
</Queues>
<NextMarker />
</EnumerationResults>