diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java
index 13280dfa7d..f22be7992b 100644
--- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java
@@ -21,8 +21,10 @@ package org.jclouds.dynect.v3;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
+import org.jclouds.dynect.v3.domain.Job;
import org.jclouds.dynect.v3.features.SessionApi;
import org.jclouds.dynect.v3.features.ZoneApi;
+import org.jclouds.javax.annotation.Nullable;
import org.jclouds.rest.annotations.Delegate;
/**
@@ -36,6 +38,15 @@ import org.jclouds.rest.annotations.Delegate;
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface DynECTApi {
+ /**
+ * returns the current status of a job.
+ *
+ * @param jobId
+ * The ID of the job
+ * @return null, if not found
+ */
+ @Nullable
+ Job getJob(long jobId);
/**
* Provides synchronous access to Session features.
diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTAsyncApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTAsyncApi.java
index 761864cd16..05da1493a2 100644
--- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTAsyncApi.java
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/DynECTAsyncApi.java
@@ -20,12 +20,24 @@ package org.jclouds.dynect.v3;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import org.jclouds.dynect.v3.domain.Job;
import org.jclouds.dynect.v3.features.SessionAsyncApi;
import org.jclouds.dynect.v3.features.ZoneAsyncApi;
+import org.jclouds.dynect.v3.filters.SessionManager;
import org.jclouds.rest.annotations.Delegate;
+import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+
+import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides access to DynECT Managed DNS through the API2 api
@@ -35,10 +47,19 @@ import org.jclouds.rest.annotations.Headers;
* @see
* @author Adrian Cole
*/
-// required for all calls
-@Produces(APPLICATION_JSON)
-@Headers(keys = "API-Version", values = "{jclouds.api-version}")
public interface DynECTAsyncApi {
+ /**
+ * @see DynECTApi#getJob
+ */
+ @Named("GetJob")
+ @GET
+ @Path("/Job/{jobId}")
+ @Produces(APPLICATION_JSON)
+ @RequestFilters(SessionManager.class)
+ @Headers(keys = "API-Version", values = "{jclouds.api-version}")
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ @Consumes(APPLICATION_JSON)
+ ListenableFuture getJob(@PathParam("jobId") long jobId);
/**
* Provides asynchronous access to Session features.
diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTRestClientModule.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTRestClientModule.java
index b803b9eb57..2f93c3a753 100644
--- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTRestClientModule.java
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTRestClientModule.java
@@ -29,8 +29,10 @@ import org.jclouds.dynect.v3.features.SessionAsyncApi;
import org.jclouds.dynect.v3.features.ZoneApi;
import org.jclouds.dynect.v3.features.ZoneAsyncApi;
import org.jclouds.dynect.v3.filters.SessionManager;
+import org.jclouds.dynect.v3.handlers.GetJobRedirectionRetryHandler;
import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.annotation.ClientError;
+import org.jclouds.http.handlers.RedirectionRetryHandler;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
@@ -61,6 +63,7 @@ public class DynECTRestClientModule extends RestClientModule {
+ public String apply(Object in) {
+ return CreatePrimaryZone.class.cast(in).getFQDN();
+ }
+ }
+}
\ No newline at end of file
diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Job.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Job.java
new file mode 100644
index 0000000000..6247997821
--- /dev/null
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Job.java
@@ -0,0 +1,99 @@
+/**
+ * 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.dynect.v3.domain;
+
+import static com.google.common.base.Objects.equal;
+import static com.google.common.base.Objects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.beans.ConstructorProperties;
+
+import javax.inject.Named;
+
+import com.google.common.base.Objects;
+
+/**
+ * @author Adrian Cole
+ */
+public final class Job {
+
+ @Named("job_id")
+ private final long id;
+ private final Status status;
+
+ @ConstructorProperties({ "job_id", "status" })
+ private Job(long id, Status status) {
+ this.id = checkNotNull(id, "id");
+ this.status = checkNotNull(status, "status for %s", id);
+ }
+
+ /**
+ * The ID of the job.
+ */
+ public long getId() {
+ return id;
+ }
+
+ /**
+ * The current status of the job.
+ */
+ public Status getStatus() {
+ return status;
+ }
+
+ public enum Status {
+ SUCCESS, FAILURE, UNRECOGNIZED;
+
+ public static Status fromValue(String status) {
+ try {
+ return valueOf(checkNotNull(status, "status").toUpperCase());
+ } catch (IllegalArgumentException e) {
+ return UNRECOGNIZED;
+ }
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(id);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null || getClass() != obj.getClass())
+ return false;
+ Job that = Job.class.cast(obj);
+ return equal(this.id, that.id);
+ }
+
+ @Override
+ public String toString() {
+ return toStringHelper(this).add("id", id).add("status", status).toString();
+ }
+
+ public static Job success(long id) {
+ return new Job(id, Status.SUCCESS);
+ }
+
+ public static Job failure(long id) {
+ return new Job(id, Status.FAILURE);
+ }
+}
diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Zone.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Zone.java
index c4cda630c3..9d064ecad7 100644
--- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Zone.java
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/Zone.java
@@ -34,7 +34,7 @@ import com.google.common.base.Objects;
*/
public final class Zone {
- private final String name;
+ private final String fqdn;
@Named("zone_type")
private final Type type;
private final int serial;
@@ -92,18 +92,18 @@ public final class Zone {
}
@ConstructorProperties({ "zone", "zone_type", "serial", "serial_style" })
- private Zone(String name, Type type, int serial, SerialStyle serialStyle) {
- this.name = checkNotNull(name, "name");
- this.type = checkNotNull(type, "type for %s", name);
- this.serial = checkNotNull(serial, "serial for %s", name);
+ private Zone(String fqdn, Type type, int serial, SerialStyle serialStyle) {
+ this.fqdn = checkNotNull(fqdn, "fqdn");
+ this.type = checkNotNull(type, "type for %s", fqdn);
+ this.serial = checkNotNull(serial, "serial for %s", fqdn);
this.serialStyle = checkNotNull(serialStyle, "serialStyle for %s", serialStyle);
}
/**
- * The name of the requested zone
+ * The fqdn of the requested zone
*/
- public String getName() {
- return name;
+ public String getFQDN() {
+ return fqdn;
}
/**
@@ -129,7 +129,7 @@ public final class Zone {
@Override
public int hashCode() {
- return Objects.hashCode(name, type);
+ return Objects.hashCode(fqdn, type);
}
@Override
@@ -139,12 +139,12 @@ public final class Zone {
if (obj == null || getClass() != obj.getClass())
return false;
Zone that = Zone.class.cast(obj);
- return equal(this.name, that.name) && equal(this.type, that.type);
+ return equal(this.fqdn, that.fqdn) && equal(this.type, that.type);
}
@Override
public String toString() {
- return toStringHelper(this).omitNullValues().add("name", name).add("type", type).add("serial", serial)
+ return toStringHelper(this).omitNullValues().add("fqdn", fqdn).add("type", type).add("serial", serial)
.add("serialStyle", serialStyle).toString();
}
@@ -157,16 +157,16 @@ public final class Zone {
}
public final static class Builder {
- private String name;
+ private String fqdn;
private Type type;
private int serial;
private SerialStyle serialStyle;
/**
- * @see Zone#getName()
+ * @see Zone#getFQDN()
*/
- public Builder name(String name) {
- this.name = name;
+ public Builder fqdn(String fqdn) {
+ this.fqdn = fqdn;
return this;
}
@@ -195,11 +195,11 @@ public final class Zone {
}
public Zone build() {
- return new Zone(name, type, serial, serialStyle);
+ return new Zone(fqdn, type, serial, serialStyle);
}
public Builder from(Zone in) {
- return this.name(in.name).type(in.type).serial(in.serial).serialStyle(in.serialStyle);
+ return this.fqdn(in.fqdn).type(in.type).serial(in.serial).serialStyle(in.serialStyle);
}
}
}
\ No newline at end of file
diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java
index 35a7f47a1b..ff3490f92e 100644
--- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java
@@ -21,7 +21,10 @@ package org.jclouds.dynect.v3.features;
import java.util.concurrent.TimeUnit;
import org.jclouds.concurrent.Timeout;
+import org.jclouds.dynect.v3.domain.CreatePrimaryZone;
+import org.jclouds.dynect.v3.domain.Job;
import org.jclouds.dynect.v3.domain.Zone;
+import org.jclouds.dynect.v3.domain.Zone.SerialStyle;
import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.FluentIterable;
@@ -38,14 +41,69 @@ public interface ZoneApi {
FluentIterable list();
/**
- * Retrieves information about the specified zone, including its nameserver
- * configuration
+ * Creates a new primary zone.
*
- * @param name
- * name of the zone to get information about. ex
- * {@code Z1PA6795UKMFR9}
+ * @param zone
+ * required parameters to create the zone.
+ * @return unpublished zone
+ */
+ Zone create(CreatePrimaryZone zone);
+
+ /**
+ * Creates a new primary zone with one hour default TTL and
+ * {@link SerialStyle#INCREMENT}
+ *
+ * @param fqdn
+ * fqdn of the zone to create {@ex. jclouds.org}
+ * @param contact
+ * email address of the contact
+ * @return unpublished zone
+ */
+ Zone createWithContact(String fqdn, String contact);
+
+ /**
+ * Retrieves information about the specified zone.
+ *
+ * @param fqdn
+ * fqdn of the zone to get information about. ex
+ * {@code jclouds.org}
* @return null if not found
*/
@Nullable
- Zone get(String name);
+ Zone get(String fqdn);
+
+ /**
+ * deletes the specified zone.
+ *
+ * @param fqdn
+ * fqdn of the zone to delete ex {@code jclouds.org}
+ * @return null if not found
+ */
+ @Nullable
+ Job delete(String fqdn);
+
+ /**
+ * Publishes the current zone
+ *
+ * @param fqdn
+ * fqdn of the zone to publish. ex
+ * {@code jclouds.org}
+ */
+ Zone publish(String fqdn);
+
+ /**
+ * freezes the specified zone.
+ *
+ * @param fqdn
+ * fqdn of the zone to freeze ex {@code jclouds.org}
+ */
+ Job freeze(String fqdn);
+
+ /**
+ * thaws the specified zone.
+ *
+ * @param fqdn
+ * fqdn of the zone to thaw ex {@code jclouds.org}
+ */
+ Job thaw(String fqdn);
}
diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneAsyncApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneAsyncApi.java
index 0be95c9cad..2ae22a9262 100644
--- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneAsyncApi.java
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneAsyncApi.java
@@ -21,20 +21,33 @@ package org.jclouds.dynect.v3.features;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
+import org.jclouds.dynect.v3.domain.Zone;
+import org.jclouds.dynect.v3.domain.CreatePrimaryZone;
+import org.jclouds.dynect.v3.domain.CreatePrimaryZone.ToFQDN;
+import org.jclouds.dynect.v3.domain.Job;
import org.jclouds.dynect.v3.domain.Zone;
import org.jclouds.dynect.v3.filters.SessionManager;
import org.jclouds.dynect.v3.functions.ExtractNames;
+import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers;
+import org.jclouds.rest.annotations.ParamParser;
+import org.jclouds.rest.annotations.Payload;
+import org.jclouds.rest.annotations.PayloadParam;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SelectJson;
import org.jclouds.rest.annotations.Transform;
import org.jclouds.rest.functions.ReturnNullOnNotFoundOr404;
+import org.jclouds.rest.binders.BindToJsonPayload;
import com.google.common.collect.FluentIterable;
import com.google.common.util.concurrent.ListenableFuture;
@@ -56,19 +69,79 @@ public interface ZoneAsyncApi {
/**
* @see ZoneApi#list
*/
- @Named("GET:ZoneList")
+ @Named("ListZones")
@GET
@SelectJson("data")
@Transform(ExtractNames.class)
ListenableFuture> list();
-
+
/**
- * @see ZoneApi#isValid
+ * @see ZoneApi#get
*/
- @Named("GET:Zone")
+ @Named("GetZone")
@GET
- @Path("/{name}")
+ @Path("/{fqdn}")
@SelectJson("data")
@ExceptionParser(ReturnNullOnNotFoundOr404.class)
- ListenableFuture get(@PathParam("name") String name);
+ ListenableFuture get(@PathParam("fqdn") String fqdn);
+
+ /**
+ * @see ZoneApi#create
+ */
+ @Named("CreatePrimaryZone")
+ @POST
+ @Path("/{fqdn}")
+ @SelectJson("data")
+ ListenableFuture create(
+ @PathParam("fqdn") @ParamParser(ToFQDN.class) @BinderParam(BindToJsonPayload.class) CreatePrimaryZone createZone);
+
+ /**
+ * @see ZoneApi#createWithContact
+ */
+ @Named("CreatePrimaryZone")
+ @POST
+ @Payload("%7B\"rname\":\"{contact}\",\"serial_style\":\"increment\",\"ttl\":3600%7D")
+ @Path("/{fqdn}")
+ @SelectJson("data")
+ ListenableFuture createWithContact(@PathParam("fqdn") String fqdn, @PayloadParam("contact") String contact);
+
+ /**
+ * @see ZoneApi#delete
+ */
+ @Named("DeleteZone")
+ @DELETE
+ @Path("/{fqdn}")
+ @ExceptionParser(ReturnNullOnNotFoundOr404.class)
+ @Consumes(APPLICATION_JSON)
+ ListenableFuture delete(@PathParam("fqdn") String fqdn);
+
+ /**
+ * @see ZoneApi#publish
+ */
+ @Named("PublishZone")
+ @PUT
+ @Payload("{\"publish\":true}")
+ @Path("/{fqdn}")
+ @SelectJson("data")
+ ListenableFuture publish(@PathParam("fqdn") String fqdn);
+
+ /**
+ * @see ZoneApi#freeze
+ */
+ @Named("FreezeZone")
+ @PUT
+ @Path("/{fqdn}")
+ @Payload("{\"freeze\":true}")
+ @Consumes(APPLICATION_JSON)
+ ListenableFuture freeze(@PathParam("fqdn") String fqdn);
+
+ /**
+ * @see ZoneApi#thaw
+ */
+ @Named("ThawZone")
+ @PUT
+ @Path("/{fqdn}")
+ @Payload("{\"thaw\":true}")
+ @Consumes(APPLICATION_JSON)
+ ListenableFuture thaw(@PathParam("fqdn") String fqdn);
}
diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/handlers/GetJobRedirectionRetryHandler.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/handlers/GetJobRedirectionRetryHandler.java
new file mode 100644
index 0000000000..2b0d99a50f
--- /dev/null
+++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/handlers/GetJobRedirectionRetryHandler.java
@@ -0,0 +1,64 @@
+/**
+ * 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.dynect.v3.handlers;
+
+import static com.google.common.net.HttpHeaders.LOCATION;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import org.jclouds.http.HttpCommand;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
+import org.jclouds.http.handlers.RedirectionRetryHandler;
+import org.jclouds.io.Payload;
+import org.jclouds.io.Payloads;
+
+/**
+ * if the redirection URL is a Job, do not replay the original request; just get
+ * the job.
+ *
+ * @author Adrian Cole
+ */
+@Singleton
+public class GetJobRedirectionRetryHandler extends RedirectionRetryHandler {
+
+ private final Payload emptyPayload;
+
+ @Inject
+ protected GetJobRedirectionRetryHandler(BackoffLimitedRetryHandler backoffHandler) {
+ super(backoffHandler);
+ this.emptyPayload = Payloads.newPayload(new byte[]{});
+ this.emptyPayload.getContentMetadata().setContentType(APPLICATION_JSON);
+ }
+
+ @Override
+ public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
+ String location = response.getFirstHeaderOrNull(LOCATION);
+ if (location != null && location.indexOf("Job") != -1) {
+ HttpRequest getRequest = command.getCurrentRequest().toBuilder()
+ .method("GET")
+ .payload(emptyPayload).build();
+ command.setCurrentRequest(getRequest);
+ }
+ return super.shouldRetryRequest(command, response);
+ }
+}
diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiExpectTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiExpectTest.java
index 420f3024eb..b1cdc9fdaf 100644
--- a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiExpectTest.java
+++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiExpectTest.java
@@ -18,12 +18,15 @@
*/
package org.jclouds.dynect.v3.features;
+import static com.google.common.net.HttpHeaders.ACCEPT;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import org.jclouds.dynect.v3.DynECTApi;
+import org.jclouds.dynect.v3.domain.CreatePrimaryZone;
import org.jclouds.dynect.v3.internal.BaseDynECTApiExpectTest;
+import org.jclouds.dynect.v3.parse.DeleteZoneResponseTest;
import org.jclouds.dynect.v3.parse.GetZoneResponseTest;
import org.jclouds.dynect.v3.parse.ListZonesResponseTest;
import org.jclouds.http.HttpRequest;
@@ -35,7 +38,6 @@ import org.testng.annotations.Test;
*/
@Test(groups = "unit", testName = "ZoneApiExpectTest")
public class ZoneApiExpectTest extends BaseDynECTApiExpectTest {
-
HttpRequest get = HttpRequest.builder().method("GET")
.endpoint("https://api2.dynect.net/REST/Zone/jclouds.org")
.addHeader("API-Version", "3.3.7")
@@ -51,8 +53,30 @@ public class ZoneApiExpectTest extends BaseDynECTApiExpectTest {
assertEquals(success.getZoneApi().get("jclouds.org").toString(),
new GetZoneResponseTest().expected().toString());
}
+
+ HttpRequest create = HttpRequest.builder().method("POST")
+ .endpoint("https://api2.dynect.net/REST/Zone/jclouds.org")
+ .addHeader("API-Version", "3.3.7")
+ .addHeader("Auth-Token", authToken)
+ .payload(stringPayload("{\"rname\":\"jimmy@jclouds.org\",\"serial_style\":\"increment\",\"ttl\":3600}"))
+ .build();
- public void testGetWhenResponseError2401() {
+ public void testCreateWhenResponseIs2xx() {
+ DynECTApi success = requestsSendResponses(createSession, createSessionResponse, create, getResponse);
+ assertEquals(success.getZoneApi().create(CreatePrimaryZone.builder()
+ .fqdn("jclouds.org")
+ .contact("jimmy@jclouds.org")
+ .build()).toString(),
+ new GetZoneResponseTest().expected().toString());
+ }
+
+ public void testCreateWithContactWhenResponseIs2xx() {
+ DynECTApi success = requestsSendResponses(createSession, createSessionResponse, create, getResponse);
+ assertEquals(success.getZoneApi().createWithContact("jclouds.org", "jimmy@jclouds.org").toString(),
+ new GetZoneResponseTest().expected().toString());
+ }
+
+ public void testGetWhenResponseIs404() {
DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, get, notFound);
assertNull(fail.getZoneApi().get("jclouds.org"));
}
@@ -72,4 +96,67 @@ public class ZoneApiExpectTest extends BaseDynECTApiExpectTest {
assertEquals(success.getZoneApi().list().toString(),
new ListZonesResponseTest().expected().toString());
}
+
+ HttpRequest delete = HttpRequest.builder().method("DELETE")
+ .endpoint("https://api2.dynect.net/REST/Zone/jclouds.org")
+ .addHeader("API-Version", "3.3.7")
+ .addHeader(ACCEPT, APPLICATION_JSON)
+ .addHeader("Auth-Token", authToken)
+ .payload(emptyJsonPayload())
+ .build();
+
+ HttpResponse deleteResponse = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResourceWithContentType("/delete_zone.json", APPLICATION_JSON)).build();
+
+ public void testDeleteWhenResponseIs2xx() {
+ DynECTApi success = requestsSendResponses(createSession, createSessionResponse, delete, deleteResponse);
+ assertEquals(success.getZoneApi().delete("jclouds.org").toString(),
+ new DeleteZoneResponseTest().expected().toString());
+ }
+
+ public void testDeleteWhenResponseIs404() {
+ DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, delete, notFound);
+ assertNull(fail.getZoneApi().delete("jclouds.org"));
+ }
+
+ HttpRequest publish = HttpRequest.builder().method("PUT")
+ .endpoint("https://api2.dynect.net/REST/Zone/jclouds.org")
+ .addHeader("API-Version", "3.3.7")
+ .addHeader("Auth-Token", authToken)
+ .payload(stringPayload("{\"publish\":true}"))
+ .build();
+
+ public void testPublishWhenResponseIs2xx() {
+ DynECTApi success = requestsSendResponses(createSession, createSessionResponse, publish, getResponse);
+ assertEquals(success.getZoneApi().publish("jclouds.org").toString(),
+ new GetZoneResponseTest().expected().toString());
+ }
+
+ HttpRequest freeze = HttpRequest.builder().method("PUT")
+ .endpoint("https://api2.dynect.net/REST/Zone/jclouds.org")
+ .addHeader("API-Version", "3.3.7")
+ .addHeader(ACCEPT, APPLICATION_JSON)
+ .addHeader("Auth-Token", authToken)
+ .payload(stringPayload("{\"freeze\":true}"))
+ .build();
+
+ public void testFreezeWhenResponseIs2xx() {
+ DynECTApi success = requestsSendResponses(createSession, createSessionResponse, freeze, deleteResponse);
+ assertEquals(success.getZoneApi().freeze("jclouds.org").toString(),
+ new DeleteZoneResponseTest().expected().toString());
+ }
+
+ HttpRequest thaw = HttpRequest.builder().method("PUT")
+ .endpoint("https://api2.dynect.net/REST/Zone/jclouds.org")
+ .addHeader("API-Version", "3.3.7")
+ .addHeader(ACCEPT, APPLICATION_JSON)
+ .addHeader("Auth-Token", authToken)
+ .payload(stringPayload("{\"thaw\":true}"))
+ .build();
+
+ public void testThawWhenResponseIs2xx() {
+ DynECTApi success = requestsSendResponses(createSession, createSessionResponse, thaw, deleteResponse);
+ assertEquals(success.getZoneApi().thaw("jclouds.org").toString(),
+ new DeleteZoneResponseTest().expected().toString());
+ }
}
diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiLiveTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiLiveTest.java
index a2eb3f05b8..0eb9e073b2 100644
--- a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiLiveTest.java
+++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/ZoneApiLiveTest.java
@@ -20,10 +20,15 @@ package org.jclouds.dynect.v3.features;
import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.logging.Logger.getAnonymousLogger;
+import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
+import org.jclouds.JcloudsVersion;
+import org.jclouds.dynect.v3.domain.Job;
+import org.jclouds.dynect.v3.domain.Job.Status;
import org.jclouds.dynect.v3.domain.Zone;
import org.jclouds.dynect.v3.internal.BaseDynECTApiLiveTest;
+import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
@@ -35,7 +40,7 @@ import com.google.common.collect.ImmutableList;
public class ZoneApiLiveTest extends BaseDynECTApiLiveTest {
private void checkZone(Zone zone) {
- checkNotNull(zone.getName(), "Name cannot be null for a Zone: %s", zone);
+ checkNotNull(zone.getFQDN(), "FQDN cannot be null for a Zone: %s", zone);
checkNotNull(zone.getSerial(), "Serial cannot be null for a Zone: %s", zone);
}
@@ -44,19 +49,74 @@ public class ZoneApiLiveTest extends BaseDynECTApiLiveTest {
ImmutableList zones = api().list().toImmutableList();
getAnonymousLogger().info("zones: " + zones.size());
- for (String zoneName : zones) {
- Zone zone = api().get(zoneName);
- checkNotNull(zone, "zone was null for Zone: %s", zoneName);
+ for (String fqdn : zones) {
+ Zone zone = api().get(fqdn);
+ checkNotNull(zone, "zone was null for Zone: %s", fqdn);
checkZone(zone);
}
}
@Test
public void testGetZoneWhenNotFound() {
- assertNull(api().get("AAAAAAAAAAAAAAAA"));
+ assertNull(api().get("AAAAAAAAAAAAAAAA.foo.com"));
+ }
+
+ @Test
+ public void testDeleteZoneWhenNotFound() {
+ assertNull(api().delete("AAAAAAAAAAAAAAAA.foo.com"));
+ }
+
+ String fqdn = System.getProperty("user.name").replace('.', '-') + ".zone.dynecttest.jclouds.org";
+ String contact = JcloudsVersion.get() + "@jclouds.org";
+
+ @Test
+ public void testCreateZone() {
+ Zone zone = api().createWithContact(fqdn, contact);
+ checkNotNull(zone, "unable to create zone %s", fqdn);
+ getAnonymousLogger().info("created zone: " + zone);
+ checkZone(zone);
+ }
+
+ @Test(dependsOnMethods = "testCreateZone")
+ public void testPublishZone() {
+ Zone zone = api().publish(fqdn);
+ checkNotNull(zone, "unable to publish zone %s", fqdn);
+ getAnonymousLogger().info("published zone: " + zone);
+ checkZone(zone);
+ }
+
+ @Test(dependsOnMethods = "testPublishZone")
+ public void testFreezeZone() {
+ Job job = api().freeze(fqdn);
+ assertEquals(job.getStatus(), Status.SUCCESS);
+ assertEquals(context.getApi().getJob(job.getId()), job);
+ // TODO: determine how to prove it is frozen
+ }
+
+ @Test(dependsOnMethods = "testFreezeZone")
+ public void testThawZone() {
+ Job job = api().thaw(fqdn);
+ assertEquals(job.getStatus(), Status.SUCCESS);
+ assertEquals(context.getApi().getJob(job.getId()), job);
+ // TODO: determine how to prove it is thawed
+ }
+
+ @Test(dependsOnMethods = "testThawZone")
+ public void testDeleteZone() {
+ Job job = api().delete(fqdn);
+ assertEquals(job.getStatus(), Status.SUCCESS);
+ assertEquals(context.getApi().getJob(job.getId()), job);
+ assertNull(api().get(fqdn), "job " + job + " didn't delete zone" + fqdn);
}
protected ZoneApi api() {
return context.getApi().getZoneApi();
}
+
+ @Override
+ @AfterClass(groups = "live")
+ protected void tearDownContext() {
+ api().delete(fqdn);
+ super.tearDownContext();
+ }
}
diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/handlers/GetJobRedirectionRetryHandlerExpectTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/handlers/GetJobRedirectionRetryHandlerExpectTest.java
new file mode 100644
index 0000000000..17456bcd04
--- /dev/null
+++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/handlers/GetJobRedirectionRetryHandlerExpectTest.java
@@ -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.dynect.v3.handlers;
+
+import static com.google.common.net.HttpHeaders.ACCEPT;
+import static com.google.common.net.HttpHeaders.LOCATION;
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+import org.jclouds.dynect.v3.DynECTApi;
+import org.jclouds.dynect.v3.internal.BaseDynECTApiExpectTest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+/**
+ *
+ * @author Adrian Cole
+ */
+@Test(groups = "unit", testName = "GetJobRedirectionRetryHandlerExpectTest")
+public class GetJobRedirectionRetryHandlerExpectTest extends BaseDynECTApiExpectTest {
+
+ public void testRedirectOnJobLocationSwitchesToGETAndNoPayload() {
+
+ HttpRequest thaw = HttpRequest.builder().method("PUT")
+ .endpoint("https://api2.dynect.net/REST/Zone/jclouds.org")
+ .addHeader("API-Version", "3.3.7")
+ .addHeader(ACCEPT, APPLICATION_JSON)
+ .addHeader("Auth-Token", authToken)
+ .payload(stringPayload("{\"thaw\":true}"))
+ .build();
+
+ HttpResponse redirectResponse = HttpResponse.builder()
+ .statusCode(317)
+ .addHeader(LOCATION, "https://api2.dynect.net/REST/Job/1234")
+ .build();
+
+ HttpRequest job = HttpRequest.builder().method("GET")
+ .endpoint("https://api2.dynect.net/REST/Job/1234")
+ .addHeader("API-Version", "3.3.7")
+ .addHeader(ACCEPT, APPLICATION_JSON)
+ .addHeader("Auth-Token", authToken)
+ .payload(emptyJsonPayload())
+ .build();
+
+ HttpResponse success = HttpResponse.builder().statusCode(200)
+ .payload(payloadFromResourceWithContentType("/delete_zone.json", APPLICATION_JSON)).build();
+
+ DynECTApi apiThatRedirects = requestsSendResponses(createSession, createSessionResponse, thaw, redirectResponse,
+ job, success);
+
+ apiThatRedirects.getZoneApi().thaw("jclouds.org");
+
+ }
+}
diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTExpectTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTExpectTest.java
index 1c50c99937..bafed021ee 100644
--- a/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTExpectTest.java
+++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/internal/BaseDynECTExpectTest.java
@@ -44,6 +44,12 @@ public class BaseDynECTExpectTest extends BaseRestApiExpectTest {
return p;
}
+ public static Payload stringPayload(String json) {
+ Payload p = Payloads.newPayload(json);
+ p.getContentMetadata().setContentType(APPLICATION_JSON);
+ return p;
+ }
+
@Override
protected HttpRequestComparisonType compareHttpRequestAsType(HttpRequest input) {
return HttpRequestComparisonType.JSON;
diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/DeleteZoneResponseTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/DeleteZoneResponseTest.java
new file mode 100644
index 0000000000..c4bd6eeb11
--- /dev/null
+++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/DeleteZoneResponseTest.java
@@ -0,0 +1,45 @@
+/**
+ * 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.dynect.v3.parse;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.core.MediaType;
+
+import org.jclouds.dynect.v3.domain.Job;
+import org.jclouds.dynect.v3.internal.BaseDynECTParseTest;
+import org.testng.annotations.Test;
+
+/**
+ * @author Adrian Cole
+ */
+@Test(groups = "unit")
+public class DeleteZoneResponseTest extends BaseDynECTParseTest {
+
+ @Override
+ public String resource() {
+ return "/delete_zone.json";
+ }
+
+ @Override
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Job expected() {
+ return Job.success(262989027l);
+ }
+}
diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetZoneResponseTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetZoneResponseTest.java
index ce2de769b6..83731f4854 100644
--- a/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetZoneResponseTest.java
+++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetZoneResponseTest.java
@@ -44,6 +44,6 @@ public class GetZoneResponseTest extends BaseDynECTParseTest {
@SelectJson("data")
@Consumes(MediaType.APPLICATION_JSON)
public Zone expected() {
- return Zone.builder().type(PRIMARY).serialStyle(INCREMENT).serial(5).name("jclouds.org").build();
+ return Zone.builder().type(PRIMARY).serialStyle(INCREMENT).serial(5).fqdn("jclouds.org").build();
}
}
\ No newline at end of file
diff --git a/labs/dynect/src/test/resources/delete_zone.json b/labs/dynect/src/test/resources/delete_zone.json
new file mode 100644
index 0000000000..aca65bef9c
--- /dev/null
+++ b/labs/dynect/src/test/resources/delete_zone.json
@@ -0,0 +1 @@
+{"status": "success", "data": {}, "job_id": 262989027, "msgs": [{"INFO": "remove: Zone removed", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]}
\ No newline at end of file