deltacloud: changed approach to use typed actions as opposed to methods like destroyInstance; validated state model

This commit is contained in:
Adrian Cole 2010-12-30 23:41:34 +01:00
parent 60b6b68556
commit d58ed7b3ac
30 changed files with 264 additions and 143 deletions

View File

@ -7,3 +7,5 @@ To install deltacloud, do the following:
To run a local deltacloud server, do the following:
* jruby
* jruby -S deltacloudd -i mock
jclouds binding to deltacloud requires a minimum server version of 0.1.0.

View File

@ -54,7 +54,7 @@
<!-- when instances are hung, open a ticket and add here -->
<jclouds.compute.blacklist-nodes>trmkrun-ccc,test.trmk-924</jclouds.compute.blacklist-nodes>
<test.deltacloud.endpoint>http://localhost:3001/api</test.deltacloud.endpoint>
<test.deltacloud.apiversion>1.0</test.deltacloud.apiversion>
<test.deltacloud.apiversion>0.1.0</test.deltacloud.apiversion>
<test.deltacloud.identity>mockuser</test.deltacloud.identity>
<test.deltacloud.credential>mockpassword</test.deltacloud.credential>
</properties>

View File

@ -23,11 +23,9 @@ import java.net.URI;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import org.jclouds.deltacloud.collections.HardwareProfiles;
@ -42,6 +40,7 @@ import org.jclouds.deltacloud.domain.Instance;
import org.jclouds.deltacloud.domain.InstanceState;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.domain.Transition;
import org.jclouds.deltacloud.functions.ReturnVoidOnRedirectedDelete;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.deltacloud.xml.DeltacloudCollectionsHandler;
import org.jclouds.deltacloud.xml.HardwareProfileHandler;
@ -53,6 +52,7 @@ import org.jclouds.deltacloud.xml.InstanceStatesHandler;
import org.jclouds.deltacloud.xml.InstancesHandler;
import org.jclouds.deltacloud.xml.RealmHandler;
import org.jclouds.deltacloud.xml.RealmsHandler;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.filters.BasicAuthentication;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.EndpointParam;
@ -62,7 +62,6 @@ import org.jclouds.rest.annotations.XMLResponseParser;
import org.jclouds.rest.functions.ReturnEmptyMultimapOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import com.google.common.collect.Multimap;
import com.google.common.util.concurrent.ListenableFuture;
@ -83,7 +82,6 @@ public interface DeltacloudAsyncClient {
* @see DeltacloudClient#getCollections
*/
@GET
@Path("")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(DeltacloudCollectionsHandler.class)
ListenableFuture<? extends Set<? extends DeltacloudCollection>> getCollections();
@ -93,7 +91,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@Endpoint(InstanceStates.class)
@Path("")
@ExceptionParser(ReturnEmptyMultimapOnNotFoundOr404.class)
@XMLResponseParser(InstanceStatesHandler.class)
ListenableFuture<? extends Multimap<InstanceState, ? extends Transition>> getInstanceStates();
@ -103,7 +100,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@Endpoint(Realms.class)
@Path("")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(RealmsHandler.class)
ListenableFuture<? extends Set<? extends Realm>> listRealms();
@ -113,7 +109,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("")
@XMLResponseParser(RealmHandler.class)
ListenableFuture<Realm> getRealm(@EndpointParam URI realmHref);
@ -122,7 +117,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@Endpoint(Images.class)
@Path("")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(ImagesHandler.class)
ListenableFuture<? extends Set<? extends Image>> listImages();
@ -132,7 +126,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("")
@XMLResponseParser(ImageHandler.class)
ListenableFuture<Image> getImage(@EndpointParam URI imageHref);
@ -141,7 +134,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@Endpoint(HardwareProfiles.class)
@Path("")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(HardwareProfilesHandler.class)
ListenableFuture<? extends Set<? extends HardwareProfile>> listHardwareProfiles();
@ -151,7 +143,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("")
@XMLResponseParser(HardwareProfileHandler.class)
ListenableFuture<HardwareProfile> getHardwareProfile(@EndpointParam URI profileHref);
@ -160,7 +151,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@Endpoint(Instances.class)
@Path("")
@ExceptionParser(ReturnEmptySetOnNotFoundOr404.class)
@XMLResponseParser(InstancesHandler.class)
ListenableFuture<? extends Set<? extends Instance>> listInstances();
@ -170,7 +160,6 @@ public interface DeltacloudAsyncClient {
*/
@GET
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
@Path("")
@XMLResponseParser(InstanceHandler.class)
ListenableFuture<Instance> getInstance(@EndpointParam URI instanceHref);
@ -179,23 +168,13 @@ public interface DeltacloudAsyncClient {
*/
@POST
@Endpoint(Instances.class)
@Path("")
@XMLResponseParser(InstanceHandler.class)
ListenableFuture<Instance> createInstance(@FormParam("image_id") String imageId, CreateInstanceOptions... options);
/**
* @see DeltacloudClient#performInstanceAction
*/
@POST
@Path("")
ListenableFuture<Void> performAction(@EndpointParam URI actionRef);
/**
* @see DeltacloudClient#deleteResource
*/
@DELETE
@ExceptionParser(ReturnVoidOnNotFoundOr404.class)
@Path("")
ListenableFuture<Void> deleteResource(@EndpointParam URI resourceHref);
@ExceptionParser(ReturnVoidOnRedirectedDelete.class)
ListenableFuture<Void> performAction(HttpRequest action);
}

View File

@ -32,7 +32,7 @@ import org.jclouds.deltacloud.domain.InstanceState;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.domain.Transition;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.http.HttpRequest;
import com.google.common.collect.Multimap;
@ -137,16 +137,9 @@ public interface DeltacloudClient {
/**
* perform a specific action.
*
* @param actionRef
* @param action
* reference from {@link Instance#getActions()}
*/
void performAction(@EndpointParam URI actionRef);
void performAction(HttpRequest action);
/**
* delete a resource, such as {@link Instance}
*
* @param resourceHref
* reference from {@link Instance#getHref()}
*/
void deleteResource(@EndpointParam URI resourceHref);
}

View File

@ -34,7 +34,7 @@ public class DeltacloudPropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_API_VERSION, "1.0");
properties.setProperty(PROPERTY_API_VERSION, "0.1.0");
return properties;
}

View File

@ -38,7 +38,9 @@ import org.jclouds.deltacloud.collections.Instances;
import org.jclouds.deltacloud.collections.Realms;
import org.jclouds.deltacloud.domain.DeltacloudCollection;
import org.jclouds.deltacloud.handlers.DeltacloudErrorHandler;
import org.jclouds.deltacloud.handlers.DeltacloudRedirectionRetryHandler;
import org.jclouds.http.HttpErrorHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.annotation.ClientError;
import org.jclouds.http.annotation.Redirection;
@ -75,7 +77,7 @@ public class DeltacloudRestClientModule extends RestClientModule<DeltacloudClien
@Override
protected void bindRetryHandlers() {
// TODO
bind(HttpRetryHandler.class).annotatedWith(Redirection.class).to(DeltacloudRedirectionRetryHandler.class);
}
protected AtomicReference<AuthorizationException> authException = new AtomicReference<AuthorizationException>();

View File

@ -27,6 +27,8 @@ import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.http.HttpRequest;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@ -45,12 +47,12 @@ public class Instance {
private final URI hardwareProfile;
private final URI realm;
private final InstanceState state;
private final Map<InstanceAction, URI> actions;
private final Map<InstanceAction, HttpRequest> actions;
private final Set<String> publicAddresses;
private final Set<String> privateAddresses;
public Instance(URI href, String id, String ownerId, @Nullable String name, URI image, URI hardwareProfile,
URI realm, InstanceState state, Map<InstanceAction, URI> actions, Set<String> publicAddresses,
URI realm, InstanceState state, Map<InstanceAction, HttpRequest> actions, Set<String> publicAddresses,
Set<String> privateAddresses) {
this.href = checkNotNull(href, "href");
this.id = checkNotNull(id, "id");
@ -135,7 +137,7 @@ public class Instance {
* @return valid actions for the instance, along with the URL which may be used to perform the
* action
*/
public Map<InstanceAction, URI> getActions() {
public Map<InstanceAction, HttpRequest> getActions() {
return actions;
}

View File

@ -0,0 +1,48 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.deltacloud.functions;
import static org.jclouds.util.Throwables2.propagateOrNull;
import javax.inject.Singleton;
import javax.ws.rs.HttpMethod;
import org.jclouds.http.HttpResponseException;
import org.jclouds.util.Throwables2;
import com.google.common.base.Function;
/**
* When a delete operation is performed, Deltacloud returns 302.
*
* @author Adrian Cole
*/
@Singleton
public class ReturnVoidOnRedirectedDelete implements Function<Exception, Void> {
public Void apply(Exception from) {
HttpResponseException exception = Throwables2.getFirstThrowableOfType(from, HttpResponseException.class);
if (exception != null && exception.getCommand().getCurrentRequest().getMethod().equals(HttpMethod.DELETE)
&& exception.getResponse().getStatusCode() == 302) {
return null;
}
return Void.class.cast(propagateOrNull(from));
}
}

View File

@ -31,7 +31,7 @@ import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Utils;
import org.jclouds.util.Strings2;
import com.google.common.base.Throwables;
import com.google.common.io.Closeables;
@ -52,7 +52,7 @@ public class DeltacloudErrorHandler implements HttpErrorHandler {
Exception exception = message != null ? new HttpResponseException(command, response, message)
: new HttpResponseException(command, response);
try {
message = message != null ? message : String.format("%s -> %s", command.getRequest().getRequestLine(),
message = message != null ? message : String.format("%s -> %s", command.getCurrentRequest().getRequestLine(),
response.getStatusLine());
switch (response.getStatusCode()) {
case 400:
@ -62,7 +62,7 @@ public class DeltacloudErrorHandler implements HttpErrorHandler {
exception = new AuthorizationException(message, exception);
break;
case 404:
if (!command.getRequest().getMethod().equals("DELETE")) {
if (!command.getCurrentRequest().getMethod().equals("DELETE")) {
exception = new ResourceNotFoundException(message, exception);
}
break;
@ -84,7 +84,7 @@ public class DeltacloudErrorHandler implements HttpErrorHandler {
if (response.getPayload() == null)
return null;
try {
return Utils.toStringAndClose(response.getPayload().getInput());
return Strings2.toStringAndClose(response.getPayload().getInput());
} catch (IOException e) {
throw new RuntimeException(e);
} finally {

View File

@ -0,0 +1,35 @@
package org.jclouds.deltacloud.handlers;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.http.handlers.RedirectionRetryHandler;
/**
* Handles Retryable responses with error codes in the 3xx range
*
* @author Adrian Cole
*/
@Singleton
public class DeltacloudRedirectionRetryHandler extends RedirectionRetryHandler {
@Inject
public DeltacloudRedirectionRetryHandler(Provider<UriBuilder> uriBuilderProvider,
BackoffLimitedRetryHandler backoffHandler) {
super(uriBuilderProvider, backoffHandler);
}
@Override
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (command.getCurrentRequest().getMethod().equals("DELETE")) {
return false;
} else {
return super.shouldRetryRequest(command, response);
}
}
}

View File

@ -26,7 +26,7 @@ import java.util.Set;
import org.jclouds.deltacloud.domain.DeltacloudCollection;
import org.jclouds.deltacloud.domain.Feature;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@ -48,7 +48,7 @@ public class DeltacloudCollectionHandler extends ParseSax.HandlerWithResult<Delt
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
if (qName.equalsIgnoreCase("link")) {
this.href = URI.create(attributes.get("href"));
this.rel = attributes.get("rel");

View File

@ -28,7 +28,7 @@ import javax.inject.Inject;
import org.jclouds.deltacloud.domain.HardwareProfile;
import org.jclouds.deltacloud.domain.HardwareProperty;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@ -60,7 +60,7 @@ public class HardwareProfileHandler extends ParseSax.HandlerWithResult<HardwareP
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
if (qName.equals("property")) {
inProperty = true;
}

View File

@ -33,7 +33,7 @@ import org.jclouds.deltacloud.domain.HardwareProperty;
import org.jclouds.deltacloud.domain.HardwareProperty.Kind;
import org.jclouds.deltacloud.domain.RangeHardwareProperty;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@ -95,7 +95,7 @@ public class HardwarePropertyHandler extends ParseSax.HandlerWithResult<Hardware
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
if (qName.equals("property")) {
this.kind = Kind.fromValue(attributes.get("kind"));
this.name = attributes.get("name");

View File

@ -24,7 +24,7 @@ import java.util.Map;
import org.jclouds.deltacloud.domain.Image;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@ -49,7 +49,7 @@ public class ImageHandler extends ParseSax.HandlerWithResult<Image> {
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
if (qName.equals("image")) {
String href = attributes.get("href");
if (href != null) {

View File

@ -23,11 +23,15 @@ import java.net.URI;
import java.util.Map;
import java.util.Set;
import javax.annotation.Resource;
import org.jclouds.deltacloud.domain.Instance;
import org.jclouds.deltacloud.domain.InstanceAction;
import org.jclouds.deltacloud.domain.InstanceState;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.jclouds.logging.Logger;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@ -40,6 +44,9 @@ import com.google.common.collect.Sets;
public class InstanceHandler extends ParseSax.HandlerWithResult<Instance> {
private StringBuilder currentText = new StringBuilder();
@Resource
protected Logger logger = Logger.NULL;
private URI href;
private String id;
private String ownerId;
@ -48,7 +55,7 @@ public class InstanceHandler extends ParseSax.HandlerWithResult<Instance> {
private URI hardwareProfile;
private URI realm;
private InstanceState state;
private Map<InstanceAction, URI> actions = Maps.newLinkedHashMap();
private Map<InstanceAction, HttpRequest> actions = Maps.newLinkedHashMap();
private Set<String> publicAddresses = Sets.newLinkedHashSet();
private Set<String> privateAddresses = Sets.newLinkedHashSet();
@ -63,7 +70,7 @@ public class InstanceHandler extends ParseSax.HandlerWithResult<Instance> {
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
if (qName.equals("public_addresses")) {
inPublicAddresses = true;
} else if (qName.equals("private_addresses")) {
@ -75,12 +82,16 @@ public class InstanceHandler extends ParseSax.HandlerWithResult<Instance> {
}
this.id = attributes.get("id");
} else if (qName.equals("link")) {
String rel = attributes.get("rel");
if (rel != null) {
InstanceAction action = InstanceAction.fromValue(rel);
try {
InstanceAction action = InstanceAction.fromValue(attributes.get("rel"));
if (action != InstanceAction.UNRECOGNIZED) {
actions.put(action, URI.create(attributes.get("href")));
HttpRequest request = new HttpRequest(attributes.get("method").toUpperCase(), URI.create(attributes
.get("href")));
actions.put(action, request);
}
} catch (RuntimeException e) {
if (logger.isDebugEnabled())
logger.warn(e, "error parsing into action: %s, %s", qName, attributes);
}
} else if (attributes.containsKey("href")) {
URI href = URI.create(attributes.get("href"));

View File

@ -27,7 +27,7 @@ import org.jclouds.deltacloud.domain.Transition;
import org.jclouds.deltacloud.domain.TransitionAutomatically;
import org.jclouds.deltacloud.domain.TransitionOnAction;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@ -48,7 +48,7 @@ public class InstanceStatesHandler extends ParseSax.HandlerWithResult<Multimap<I
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
if (qName.equals("state")) {
state = InstanceState.valueOf(attributes.get("name").toUpperCase());
} else if (qName.equals("transition")) {

View File

@ -25,7 +25,7 @@ import java.util.Map;
import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.domain.RealmState;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.util.Utils;
import org.jclouds.util.SaxUtils;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@ -49,7 +49,7 @@ public class RealmHandler extends ParseSax.HandlerWithResult<Realm> {
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
Map<String, String> attributes = Utils.cleanseAttributes(attrs);
Map<String, String> attributes = SaxUtils.cleanseAttributes(attrs);
if (attributes.containsKey("href")) {
this.href = URI.create(attributes.get("href"));
this.id = attributes.get("id");

View File

@ -29,6 +29,7 @@ import java.util.Set;
import org.jclouds.deltacloud.config.DeltacloudRestClientModule;
import org.jclouds.deltacloud.domain.DeltacloudCollection;
import org.jclouds.deltacloud.functions.ReturnVoidOnRedirectedDelete;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.deltacloud.xml.DeltacloudCollectionsHandler;
import org.jclouds.deltacloud.xml.HardwareProfileHandler;
@ -49,11 +50,9 @@ import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextSpec;
import org.jclouds.rest.functions.MapHttp4xxCodesToExceptions;
import org.jclouds.rest.functions.ReturnEmptyMultimapOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnEmptySetOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
@ -65,23 +64,24 @@ import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests annotation parsing of {@code DeltacloudAsyncClient}
* Tests behavior of {@code DeltacloudAsyncClient}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "deltacloud.DeltacloudAsyncClientTest")
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "DeltacloudAsyncClientTest")
public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncClient> {
public void testGetCollections() throws SecurityException, NoSuchMethodException, IOException {
Method method = DeltacloudAsyncClient.class.getMethod("getCollections");
GeneratedHttpRequest<DeltacloudAsyncClient> httpRequest = processor.createRequest(method);
HttpRequest httpRequest = processor.createRequest(method);
assertRequestLineEquals(httpRequest, "GET http://localhost:3001/api HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "Accept: application/xml\n");
assertPayloadEquals(httpRequest, null, null, false);
// now make sure request filters apply by replaying
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
httpRequest = Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
httpRequest = Iterables.getOnlyElement(httpRequest.getFilters()).filter(httpRequest);
assertRequestLineEquals(httpRequest, "GET http://localhost:3001/api HTTP/1.1");
// for example, using basic authentication, we should get "only one"
@ -268,8 +268,9 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
}
public void testPerformAction() throws IOException, SecurityException, NoSuchMethodException {
Method method = DeltacloudAsyncClient.class.getMethod("performAction", URI.class);
HttpRequest request = processor.createRequest(method, URI.create("https://delta/instance1/reboot"));
Method method = DeltacloudAsyncClient.class.getMethod("performAction", HttpRequest.class);
HttpRequest request = processor.createRequest(method,
HttpRequest.builder().method("POST").endpoint(URI.create("https://delta/instance1/reboot")).build());
assertRequestLineEquals(request, "POST https://delta/instance1/reboot HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/xml\n");
@ -277,22 +278,7 @@ public class DeltacloudAsyncClientTest extends RestClientTest<DeltacloudAsyncCli
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, MapHttp4xxCodesToExceptions.class);
checkFilters(request);
}
public void testDeleteResource() throws IOException, SecurityException, NoSuchMethodException {
Method method = DeltacloudAsyncClient.class.getMethod("deleteResource", URI.class);
HttpRequest request = processor.createRequest(method, URI.create("https://delta/instance1"));
assertRequestLineEquals(request, "DELETE https://delta/instance1 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Accept: application/xml\n");
assertPayloadEquals(request, null, null, false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, ReturnVoidOnNotFoundOr404.class);
assertExceptionParserClassEquals(method, ReturnVoidOnRedirectedDelete.class);
checkFilters(request);
}

View File

@ -24,7 +24,6 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import java.io.IOException;
import java.net.URI;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -41,6 +40,7 @@ import org.jclouds.deltacloud.domain.Realm;
import org.jclouds.deltacloud.domain.Transition;
import org.jclouds.deltacloud.options.CreateInstanceOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRequest;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.net.IPSocket;
import org.jclouds.predicates.InetSocketAddressConnect;
@ -55,6 +55,7 @@ import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
@ -122,18 +123,24 @@ public class DeltacloudClientLiveTest {
public void testGetInstanceStatesCanGoFromStartToFinish() throws Exception {
Multimap<InstanceState, ? extends Transition> states = client.getInstanceStates();
assertNotNull(states);
Iterable<Transition> fromStart = findChainToFinish(InstanceState.START, states);
assert Iterables.size(fromStart) > 0 : fromStart;
Iterable<Transition> toFinishFromStart = findChainTo(InstanceState.FINISH, InstanceState.START, states);
assert Iterables.size(toFinishFromStart) > 0 : toFinishFromStart;
Iterable<Transition> toRunningFromStart = findChainTo(InstanceState.RUNNING, InstanceState.START, states);
assert Iterables.size(toRunningFromStart) > 0 : toRunningFromStart;
Iterable<Transition> toFinishFromRunning = findChainTo(InstanceState.FINISH, InstanceState.RUNNING, states);
assert Iterables.size(toFinishFromRunning) > 0 : toFinishFromRunning;
assertEquals(ImmutableList.copyOf(Iterables.concat(toRunningFromStart, toFinishFromRunning)),
ImmutableList.copyOf(toFinishFromStart));
}
Iterable<Transition> findChainToFinish(InstanceState currentState,
Iterable<Transition> findChainTo(InstanceState desired, InstanceState currentState,
Multimap<InstanceState, ? extends Transition> states) {
for (Transition transition : states.get(currentState)) {
if (currentState.ordinal() >= transition.getTo().ordinal())
continue;
if (transition.getTo() == InstanceState.FINISH)
if (transition.getTo() == desired)
return ImmutableSet.<Transition> of(transition);
Iterable<Transition> transitions = findChainToFinish(transition.getTo(), states);
Iterable<Transition> transitions = findChainTo(desired, transition.getTo(), states);
if (Iterables.size(transitions) > 0)
return Iterables.concat(ImmutableSet.of(transition), transitions);
}
@ -223,7 +230,7 @@ public class DeltacloudClientLiveTest {
return null;
}
public URI refreshInstanceAndGetAction(InstanceAction action) {
public HttpRequest refreshInstanceAndGetAction(InstanceAction action) {
return client.getInstance(instance.getHref()).getActions().get(action);
}
@ -243,12 +250,12 @@ public class DeltacloudClientLiveTest {
@Test(dependsOnMethods = "testLifeCycle")
public void testDestroyInstance() throws Exception {
try {
client.deleteResource(instance.getHref());
} catch (IllegalArgumentException e) {
client.performAction(refreshInstanceAndGetAction(InstanceAction.STOP));
client.deleteResource(instance.getHref());
assertEquals(client.getInstance(instance.getHref()), null);
assertEquals(client.getInstance(instance.getHref()).getState(), InstanceState.STOPPED);
} catch (IllegalArgumentException e) {
}
client.performAction(refreshInstanceAndGetAction(InstanceAction.DESTROY));
assertEquals(client.getInstance(instance.getHref()), null);
}
protected void doConnectViaSsh(Instance instance, Credentials creds) throws IOException {
@ -270,7 +277,7 @@ public class DeltacloudClientLiveTest {
@AfterGroups(groups = "live")
protected void tearDown() {
try {
client.deleteResource(instance.getHref());
// client.deleteResource(instance.getHref());
} catch (Exception e) {
// no need to check null or anything as we swallow all
}

View File

@ -34,7 +34,7 @@ import org.jclouds.http.HttpResponse;
import org.jclouds.io.Payloads;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Utils;
import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.inject.Guice;
@ -87,11 +87,11 @@ public class DeltacloudErrorHandlerTest {
HttpCommand command = createMock(HttpCommand.class);
HttpRequest request = new HttpRequest(method, uri);
HttpResponse response = new HttpResponse(statusCode, message, Payloads.newInputStreamPayload(Utils
HttpResponse response = new HttpResponse(statusCode, message, Payloads.newInputStreamPayload(Strings2
.toInputStream(content)));
response.getPayload().getContentMetadata().setContentType(contentType);
expect(command.getRequest()).andReturn(request).atLeastOnce();
expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
command.setException(classEq(expected));
replay(command);

View File

@ -0,0 +1,67 @@
package org.jclouds.deltacloud.handlers;
import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify;
import java.net.URI;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.BaseRestClientTest.MockModule;
import org.jclouds.rest.config.RestModule;
import org.testng.annotations.Test;
import com.google.inject.Guice;
/**
* Tests behavior of {@code DeltacloudRedirectionRetry}
*
* @author Adrian Cole
*/
@Test(groups = "unit")
public class DeltacloudRedirectionRetryHandlerTest {
@Test
public void test302DoesNotRetryOnDelete() {
HttpCommand command = createMock(HttpCommand.class);
HttpRequest request = HttpRequest.builder().method("DELETE").endpoint(URI.create("http://localhost")).build();
HttpResponse response = new HttpResponse(302, "HTTP/1.1 302 Found", null);
expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
replay(command);
DeltacloudRedirectionRetryHandler retry = Guice.createInjector(new MockModule(), new RestModule()).getInstance(
DeltacloudRedirectionRetryHandler.class);
assert !retry.shouldRetryRequest(command, response);
verify(command);
}
@Test
public void test302DoesRetryOnGET() {
HttpCommand command = createMock(HttpCommand.class);
HttpRequest request = HttpRequest.builder().method("GET").endpoint(URI.create("http://localhost")).build();
HttpResponse response = new HttpResponse(302, "HTTP/1.1 302 Found", null);
expect(command.getCurrentRequest()).andReturn(request).atLeastOnce();
expect(command.incrementRedirectCount()).andReturn(1);
replay(command);
DeltacloudRedirectionRetryHandler retry = Guice.createInjector(new MockModule(), new RestModule()).getInstance(
DeltacloudRedirectionRetryHandler.class);
assert !retry.shouldRetryRequest(command, response);
verify(command);
}
}

View File

@ -37,7 +37,8 @@ import com.google.common.collect.ImmutableSet;
*
* @author Adrian Cole
*/
@Test(groups = "unit")
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "DeltacloudCollectionsHandlerTest")
public class DeltacloudCollectionsHandlerTest extends BaseHandlerTest {
public void test() {
@ -56,9 +57,6 @@ public class DeltacloudCollectionsHandlerTest extends BaseHandlerTest {
URI.create("http://localhost:3001/api/buckets"), "buckets")
);
// not sure why this isn"t always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(DeltacloudCollectionsHandler.class)).parse(is), expects);
}
}

View File

@ -41,7 +41,8 @@ import com.google.common.collect.ImmutableSet;
*
* @author Adrian Cole
*/
@Test(groups = "unit")
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "HardwareProfilesHandlerTest")
public class HardwareProfilesHandlerTest extends BaseHandlerTest {
@Test
@ -74,11 +75,6 @@ public class HardwareProfilesHandlerTest extends BaseHandlerTest {
new FixedHardwareProperty("architecture", "label", "x86_64"))),
new HardwareProfile(URI.create("http://localhost:3001/api/hardware_profiles/opaque"), "opaque", "opaque",
ImmutableSet.<HardwareProperty> of()));
System.out.println(factory);
System.out.println(injector);
// not sure why this isn't always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(HardwareProfilesHandler.class)).parse(is), expects);
}
}

View File

@ -37,7 +37,8 @@ import com.google.common.collect.ImmutableSet;
*
* @author Adrian Cole
*/
@Test(groups = "unit")
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "ImagesHandlerTest")
public class ImagesHandlerTest extends BaseHandlerTest {
@Test
@ -50,11 +51,6 @@ public class ImagesHandlerTest extends BaseHandlerTest {
"fedoraproject", "Fedora 10", "Fedora 10", "i386"),
new Image(URI.create("http://fancycloudprovider.com/api/images/img3"), "img3", "ted", "JBoss", "JBoss",
"i386"));
System.out.println(factory);
System.out.println(injector);
// not sure why this isn't always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(ImagesHandler.class)).parse(is), expects);
}
}

View File

@ -27,6 +27,7 @@ import java.net.URI;
import org.jclouds.deltacloud.domain.Instance;
import org.jclouds.deltacloud.domain.InstanceAction;
import org.jclouds.deltacloud.domain.InstanceState;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.config.SaxParserModule;
import org.testng.annotations.Test;
@ -61,12 +62,14 @@ public class InstanceHandlerTest {
}
public void test() {
Instance expects = new Instance(URI.create("http://fancycloudprovider.com/api/instances/inst1"), "inst1", "larry",
"Production JBoss Instance", URI.create("http://fancycloudprovider.com/api/images/img3"),
Instance expects = new Instance(URI.create("http://fancycloudprovider.com/api/instances/inst1"), "inst1",
"larry", "Production JBoss Instance", URI.create("http://fancycloudprovider.com/api/images/img3"),
URI.create("http://fancycloudprovider.com/api/hardware_profiles/m1-small"),
URI.create("http://fancycloudprovider.com/api/realms/us"), InstanceState.RUNNING, ImmutableMap.of(
InstanceAction.REBOOT, URI.create("http://fancycloudprovider.com/api/instances/inst1/reboot"),
InstanceAction.STOP, URI.create("http://fancycloudprovider.com/api/instances/inst1/stop")),
InstanceAction.REBOOT,
new HttpRequest("POST", URI.create("http://fancycloudprovider.com/api/instances/inst1/reboot")),
InstanceAction.STOP,
new HttpRequest("POST", URI.create("http://fancycloudprovider.com/api/instances/inst1/stop"))),
ImmutableSet.of("inst1.larry.fancycloudprovider.com"), ImmutableSet.of("inst1.larry.internal"));
assertEquals(parseInstance(), expects);
}

View File

@ -39,7 +39,8 @@ import com.google.common.collect.Multimap;
*
* @author Adrian Cole
*/
@Test(groups = "unit")
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "InstanceStatesHandlerTest")
public class InstanceStatesHandlerTest extends BaseHandlerTest {
public void test() {
@ -52,9 +53,6 @@ public class InstanceStatesHandlerTest extends BaseHandlerTest {
new TransitionOnAction(InstanceAction.STOP, InstanceState.STOPPED))
.putAll(InstanceState.STOPPED, new TransitionOnAction(InstanceAction.START, InstanceState.RUNNING),
new TransitionOnAction(InstanceAction.DESTROY, InstanceState.FINISH)).build();
// not sure why this isn"t always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(InstanceStatesHandler.class)).parse(is).entries(),
expects.entries());

View File

@ -28,6 +28,7 @@ import java.util.Set;
import org.jclouds.deltacloud.domain.Instance;
import org.jclouds.deltacloud.domain.InstanceAction;
import org.jclouds.deltacloud.domain.InstanceState;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
@ -39,7 +40,8 @@ import com.google.common.collect.ImmutableSet;
*
* @author Adrian Cole
*/
@Test(groups = "unit")
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "InstancesHandlerTest")
public class InstancesHandlerTest extends BaseHandlerTest {
@Test
@ -50,14 +52,11 @@ public class InstancesHandlerTest extends BaseHandlerTest {
"Production JBoss Instance", URI.create("http://fancycloudprovider.com/api/images/img3"), URI
.create("http://fancycloudprovider.com/api/hardware_profiles/m1-small"), URI
.create("http://fancycloudprovider.com/api/realms/us"), InstanceState.RUNNING, ImmutableMap.of(
InstanceAction.REBOOT, URI.create("http://fancycloudprovider.com/api/instances/inst1/reboot"),
InstanceAction.STOP, URI.create("http://fancycloudprovider.com/api/instances/inst1/stop")),
InstanceAction.REBOOT,
new HttpRequest("POST", URI.create("http://fancycloudprovider.com/api/instances/inst1/reboot")),
InstanceAction.STOP,
new HttpRequest("POST", URI.create("http://fancycloudprovider.com/api/instances/inst1/stop"))),
ImmutableSet.of("inst1.larry.fancycloudprovider.com"), ImmutableSet.of("inst1.larry.internal")));
System.out.println(factory);
System.out.println(injector);
// not sure why this isn't always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(InstancesHandler.class)).parse(is), expects);
}
}

View File

@ -37,7 +37,8 @@ import com.google.common.collect.ImmutableSet;
*
* @author Adrian Cole
*/
@Test(groups = "unit")
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "RealmsHandlerTest")
public class RealmsHandlerTest extends BaseHandlerTest {
@Test
@ -47,8 +48,6 @@ public class RealmsHandlerTest extends BaseHandlerTest {
new Realm(URI.create("http://fancycloudprovider.com/api/realms/us"), "us", "United States", null,
RealmState.AVAILABLE), new Realm(URI.create("http://fancycloudprovider.com/api/realms/eu"), "eu",
"Europe", null, RealmState.AVAILABLE));
// not sure why this isn't always automatically called from surefire.
setUpInjector();
assertEquals(factory.create(injector.getInstance(RealmsHandler.class)).parse(is), expects);
}
}

View File

@ -7,8 +7,8 @@
<state>RUNNING</state>
<actions>
<link rel="reboot" href="http://fancycloudprovider.com/api/instances/inst1/reboot"/>
<link rel="stop" href="http://fancycloudprovider.com/api/instances/inst1/stop"/>
<link rel="reboot" href="http://fancycloudprovider.com/api/instances/inst1/reboot" method="post" />
<link rel="stop" href="http://fancycloudprovider.com/api/instances/inst1/stop" method="post" />
</actions>
<public_addresses>
<address>inst1.larry.fancycloudprovider.com</address>

View File

@ -8,8 +8,8 @@
<state>RUNNING</state>
<actions>
<link rel="reboot" href="http://fancycloudprovider.com/api/instances/inst1/reboot"/>
<link rel="stop" href="http://fancycloudprovider.com/api/instances/inst1/stop"/>
<link rel="reboot" href="http://fancycloudprovider.com/api/instances/inst1/reboot" method="post" />
<link rel="stop" href="http://fancycloudprovider.com/api/instances/inst1/stop" method="post" />
</actions>
<public_addresses>
<address>inst1.larry.fancycloudprovider.com</address>