From 31102571b47af2a9646c04d76095569feb5cd822 Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Sun, 3 Mar 2013 11:56:44 -0800 Subject: [PATCH] added record crud for dynect --- .../dynect/v3/domain/CreateRecord.java | 163 +++++++++++++++++ .../jclouds/dynect/v3/features/RecordApi.java | 62 ++++++- .../dynect/v3/features/RecordAsyncApi.java | 61 +++++++ .../v3/features/RecordApiExpectTest.java | 169 ++++++++++++------ .../dynect/v3/features/RecordApiLiveTest.java | 93 +++++++++- .../src/test/resources/delete_record.json | 1 + .../dynect/src/test/resources/new_record.json | 1 + labs/dynect/src/test/resources/new_zone.json | 1 + 8 files changed, 496 insertions(+), 55 deletions(-) create mode 100644 labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/CreateRecord.java create mode 100644 labs/dynect/src/test/resources/delete_record.json create mode 100644 labs/dynect/src/test/resources/new_record.json create mode 100644 labs/dynect/src/test/resources/new_zone.json diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/CreateRecord.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/CreateRecord.java new file mode 100644 index 0000000000..4f298a5c55 --- /dev/null +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/domain/CreateRecord.java @@ -0,0 +1,163 @@ +/** + * 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, String 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.util.Map; + +import com.google.common.base.Objects; +import com.google.common.primitives.UnsignedInteger; + +/** + * @author Adrian Cole + */ +public class CreateRecord> { + + private final String fqdn; + private final String type; + private final UnsignedInteger ttl; + private final D rdata; + + private CreateRecord(String fqdn, String type, UnsignedInteger ttl, D rdata) { + this.fqdn = checkNotNull(fqdn, "fqdn"); + this.type = checkNotNull(type, "type of %s", fqdn); + this.ttl = checkNotNull(ttl, "ttl of %s", fqdn); + this.rdata = checkNotNull(rdata, "rdata of %s", fqdn); + } + + /** + * @see RecordId#getFQDN() + */ + public String getFQDN() { + return fqdn; + } + + /** + * @see RecordId#getType() + */ + public String getType() { + return type; + } + + /** + * zero for zone default + * + * @see Record#getTTL() + */ + public UnsignedInteger getTTL() { + return ttl; + } + + /** + * @see Record#getRData() + */ + public D getRData() { + return rdata; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || !obj.getClass().equals(CreateRecord.class)) + return false; + CreateRecord that = CreateRecord.class.cast(obj); + return equal(this.fqdn, that.fqdn) && equal(this.type, that.type) && equal(this.ttl, that.ttl) + && equal(this.rdata, that.rdata); + } + + @Override + public String toString() { + return toStringHelper(this).add("fqdn", fqdn).add("type", type).add("ttl", ttl).add("rdata", rdata).toString(); + } + + @Override + public int hashCode() { + return Objects.hashCode(fqdn, type, ttl, rdata); + } + + public static > Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().from(this); + } + + public static class Builder> { + protected String fqdn; + protected String type; + protected UnsignedInteger ttl = UnsignedInteger.ZERO; + protected D rdata; + + /** + * @see CreateRecord#getFQDN() + */ + public Builder fqdn(String fqdn) { + this.fqdn = fqdn; + return this; + } + + /** + * @see CreateRecord#getType() + */ + public Builder type(String type) { + this.type = type; + return this; + } + + /** + * @see CreateRecord#getTTL() + */ + public Builder ttl(UnsignedInteger ttl) { + this.ttl = ttl; + return this; + } + + /** + * @see CreateRecord#getTTL() + */ + public Builder ttl(int ttl) { + return ttl(UnsignedInteger.fromIntBits(ttl)); + } + + /** + * @see CreateRecord#getRData() + */ + public Builder rdata(D rdata) { + this.rdata = rdata; + return this; + } + + public CreateRecord build() { + return new CreateRecord(fqdn, type, ttl, rdata); + } + + public Builder from(CreateRecord in) { + return fqdn(in.fqdn).type(in.type).ttl(in.ttl).rdata(in.rdata); + } + + public Builder from(Record in) { + return fqdn(in.getFQDN()).type(in.getType()).ttl(in.getTTL()).rdata(in.getRData()); + } + } +} \ No newline at end of file diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordApi.java index 63a019b57e..b0a51bc58b 100644 --- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordApi.java +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordApi.java @@ -21,6 +21,8 @@ package org.jclouds.dynect.v3.features; import java.util.Map; import org.jclouds.dynect.v3.DynECTExceptions.JobStillRunningException; +import org.jclouds.dynect.v3.domain.CreateRecord; +import org.jclouds.dynect.v3.domain.Job; import org.jclouds.dynect.v3.domain.Record; import org.jclouds.dynect.v3.domain.RecordId; import org.jclouds.dynect.v3.domain.SOARecord; @@ -32,6 +34,7 @@ import org.jclouds.dynect.v3.domain.rdata.NSData; import org.jclouds.dynect.v3.domain.rdata.PTRData; import org.jclouds.dynect.v3.domain.rdata.SRVData; import org.jclouds.dynect.v3.domain.rdata.TXTData; +import org.jclouds.javax.annotation.Nullable; import com.google.common.collect.FluentIterable; @@ -41,15 +44,52 @@ import com.google.common.collect.FluentIterable; */ public interface RecordApi { /** - * Retrieves a list of resource record ids for all records of any type in the - * given zone throws JobStillRunningException; + * Retrieves a list of resource record ids for all records of any type in the given zone. + * + * @throws JobStillRunningException + * if a different job in the session is still running */ FluentIterable list() throws JobStillRunningException; + /** + * Retrieves a list of resource record ids for all records of the fqdn and type in the given zone + * + * @throws JobStillRunningException + * if a different job in the session is still running + */ + FluentIterable listByFQDNAndType(String fqdn, String type) throws JobStillRunningException; + + /** + * Schedules addition of a new record into the current session. Calling {@link ZoneApi#publish(String)} will publish + * the zone, creating the record. + * + * @param newRecord + * record to create + * @return job relating to the scheduled creation. + * @throws JobStillRunningException + * if a different job in the session is still running + */ + Job scheduleCreate(CreateRecord newRecord) throws JobStillRunningException; + + /** + * Schedules deletion of a record into the current session. Calling {@link ZoneApi#publish(String)} will publish the + * changes, deleting the record. + * + * @param recordId + * record to delete + * @return job relating to the scheduled deletion or null, if the record never existed. + * @throws JobStillRunningException + * if a different job in the session is still running + */ + @Nullable + Job scheduleDelete(RecordId recordId) throws JobStillRunningException; + /** * retrieves a resource record without regard to type * * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record> get(RecordId recordId) throws JobStillRunningException; @@ -61,6 +101,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getAAAA(String fqdn, long recordId) throws JobStillRunningException; @@ -72,6 +114,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getA(String fqdn, long recordId) throws JobStillRunningException; @@ -83,6 +127,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getCNAME(String fqdn, long recordId) throws JobStillRunningException; @@ -94,6 +140,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getMX(String fqdn, long recordId) throws JobStillRunningException; @@ -105,6 +153,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getNS(String fqdn, long recordId) throws JobStillRunningException; @@ -116,6 +166,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getPTR(String fqdn, long recordId) throws JobStillRunningException; @@ -127,6 +179,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ SOARecord getSOA(String fqdn, long recordId) throws JobStillRunningException; @@ -138,6 +192,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getSRV(String fqdn, long recordId) throws JobStillRunningException; @@ -149,6 +205,8 @@ public interface RecordApi { * @param recordId * {@link RecordId#getId()} * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running */ Record getTXT(String fqdn, long recordId) throws JobStillRunningException; } \ No newline at end of file diff --git a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordAsyncApi.java b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordAsyncApi.java index 20fce2b54f..6902a818d4 100644 --- a/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordAsyncApi.java +++ b/labs/dynect/src/main/java/org/jclouds/dynect/v3/features/RecordAsyncApi.java @@ -19,18 +19,26 @@ package org.jclouds.dynect.v3.features; import static com.google.common.base.Preconditions.checkNotNull; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.jclouds.http.Uris.uriBuilder; import java.net.URI; import java.util.Map; +import javax.inject.Inject; 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.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import org.jclouds.Fallbacks.NullOnNotFoundOr404; import org.jclouds.dynect.v3.DynECTExceptions.JobStillRunningException; +import org.jclouds.dynect.v3.domain.CreateRecord; +import org.jclouds.dynect.v3.domain.Job; import org.jclouds.dynect.v3.domain.Record; import org.jclouds.dynect.v3.domain.RecordId; import org.jclouds.dynect.v3.domain.SOARecord; @@ -46,6 +54,7 @@ import org.jclouds.dynect.v3.filters.AlwaysAddContentType; import org.jclouds.dynect.v3.filters.SessionManager; import org.jclouds.dynect.v3.functions.ToRecordIds; import org.jclouds.http.HttpRequest; +import org.jclouds.json.Json; import org.jclouds.rest.Binder; import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.Fallback; @@ -78,6 +87,58 @@ public interface RecordAsyncApi { @ResponseParser(ToRecordIds.class) ListenableFuture> list() throws JobStillRunningException; + /** + * @see RecordApi#listByFQDNAndType + */ + @Named("GetRecord") + @GET + @Path("/{type}Record/{zone}/{fqdn}") + @ResponseParser(ToRecordIds.class) + ListenableFuture> listByFQDNAndType(@PathParam("fqdn") String fqdn, + @PathParam("type") String type) throws JobStillRunningException; + + /** + * @see RecordApi#scheduleCreate + */ + @Named("CreateRecord") + @POST + @Path("/{type}Record/{zone}/{fqdn}") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + ListenableFuture scheduleCreate(@BinderParam(CreateRecordBinder.class) CreateRecord newRecord) + throws JobStillRunningException; + + static class CreateRecordBinder implements Binder { + private final Json json; + + @Inject + CreateRecordBinder(Json json){ + this.json = checkNotNull(json, "json"); + } + + @SuppressWarnings("unchecked") + @Override + public R bindToRequest(R request, Object arg) { + CreateRecord in = CreateRecord.class.cast(checkNotNull(arg, "record to create")); + URI path = uriBuilder(request.getEndpoint()) + .build(ImmutableMap. builder() + .put("type", in.getType()) + .put("fqdn", in.getFQDN()).build()); + return (R) request.toBuilder() + .endpoint(path) + .payload(json.toJson(ImmutableMap.of("rdata", ImmutableMap.copyOf(in.getRData()), "ttl", in.getTTL().intValue()))).build(); + } + } + + /** + * @see RecordApi#scheduleDelete + */ + @Named("DeleteRecord") + @DELETE + @Fallback(NullOnNotFoundOr404.class) + @Consumes(APPLICATION_JSON) + ListenableFuture scheduleDelete(@BinderParam(RecordIdBinder.class) RecordId recordId) throws JobStillRunningException; + /** * @see RecordApi#get */ diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiExpectTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiExpectTest.java index ea4e5e78fe..aea0721c6a 100644 --- a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiExpectTest.java +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiExpectTest.java @@ -19,13 +19,18 @@ package org.jclouds.dynect.v3.features; import static com.google.common.net.HttpHeaders.CONTENT_TYPE; +import static com.google.common.net.HttpHeaders.ACCEPT; import static javax.ws.rs.core.MediaType.APPLICATION_JSON; import static org.jclouds.dynect.v3.domain.RecordId.recordIdBuilder; +import static org.jclouds.dynect.v3.domain.rdata.AData.a; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; import org.jclouds.dynect.v3.DynECTApi; +import org.jclouds.dynect.v3.domain.CreateRecord; +import org.jclouds.dynect.v3.domain.Job; import org.jclouds.dynect.v3.domain.RecordId; +import org.jclouds.dynect.v3.domain.rdata.AData; import org.jclouds.dynect.v3.internal.BaseDynECTApiExpectTest; import org.jclouds.dynect.v3.parse.GetAAAARecordResponseTest; import org.jclouds.dynect.v3.parse.GetARecordResponseTest; @@ -48,33 +53,33 @@ import org.testng.annotations.Test; @Test(groups = "unit", testName = "RecordApiExpectTest") public class RecordApiExpectTest extends BaseDynECTApiExpectTest { HttpRequest getSOA = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/SOARecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") - .addHeader("API-Version", "3.3.8") - .addHeader(CONTENT_TYPE, APPLICATION_JSON) - .addHeader("Auth-Token", authToken).build(); + .endpoint("https://api2.dynect.net/REST/SOARecord/jclouds.org/jclouds.org/50976579") + .addHeader("API-Version", "3.3.8") + .addHeader(CONTENT_TYPE, APPLICATION_JSON) + .addHeader("Auth-Token", authToken).build(); HttpResponse soaResponse = HttpResponse.builder().statusCode(200) .payload(payloadFromResourceWithContentType("/get_record_soa.json", APPLICATION_JSON)).build(); RecordId soaId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("SOA") .id(50976579l).build(); public void testGetWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getSOA, soaResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").get(soaId).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").get(soaId).toString(), new GetRecordResponseTest().expected().toString()); } public void testGetWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getSOA, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").get(soaId)); + assertNull(fail.getRecordApiForZone("jclouds.org").get(soaId)); } HttpRequest getAAAA = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/AAAARecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/AAAARecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -83,24 +88,24 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_aaaa.json", APPLICATION_JSON)).build(); RecordId aaaaId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("AAAA") .id(50976579l).build(); public void testGetAAAAWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getAAAA, aaaaResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getAAAA(aaaaId.getFQDN(), aaaaId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getAAAA(aaaaId.getFQDN(), aaaaId.getId()).toString(), new GetAAAARecordResponseTest().expected().toString()); } public void testGetAAAAWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getAAAA, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getAAAA(aaaaId.getFQDN(), aaaaId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getAAAA(aaaaId.getFQDN(), aaaaId.getId())); } HttpRequest getA = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/ARecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/ARecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -109,24 +114,24 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_a.json", APPLICATION_JSON)).build(); RecordId aId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("A") .id(50976579l).build(); public void testGetAWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getA, aResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getA(aId.getFQDN(), aId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getA(aId.getFQDN(), aId.getId()).toString(), new GetARecordResponseTest().expected().toString()); } public void testGetAWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getA, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getA(aId.getFQDN(), aId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getA(aId.getFQDN(), aId.getId())); } HttpRequest getCNAME = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/CNAMERecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/CNAMERecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -135,24 +140,24 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_cname.json", APPLICATION_JSON)).build(); RecordId cnameId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("CNAME") .id(50976579l).build(); public void testGetCNAMEWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getCNAME, cnameResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getCNAME(cnameId.getFQDN(), cnameId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getCNAME(cnameId.getFQDN(), cnameId.getId()).toString(), new GetCNAMERecordResponseTest().expected().toString()); } public void testGetCNAMEWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getCNAME, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getCNAME(cnameId.getFQDN(), cnameId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getCNAME(cnameId.getFQDN(), cnameId.getId())); } HttpRequest getMX = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/MXRecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/MXRecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -161,24 +166,24 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_mx.json", APPLICATION_JSON)).build(); RecordId mxId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("MX") .id(50976579l).build(); public void testGetMXWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getMX, mxResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getMX(mxId.getFQDN(), mxId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getMX(mxId.getFQDN(), mxId.getId()).toString(), new GetMXRecordResponseTest().expected().toString()); } public void testGetMXWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getMX, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getMX(mxId.getFQDN(), mxId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getMX(mxId.getFQDN(), mxId.getId())); } HttpRequest getNS = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/NSRecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/NSRecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -187,24 +192,24 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_ns.json", APPLICATION_JSON)).build(); RecordId nsId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("NS") .id(50976579l).build(); public void testGetNSWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getNS, nsResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getNS(nsId.getFQDN(), nsId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getNS(nsId.getFQDN(), nsId.getId()).toString(), new GetNSRecordResponseTest().expected().toString()); } public void testGetNSWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getNS, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getNS(nsId.getFQDN(), nsId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getNS(nsId.getFQDN(), nsId.getId())); } HttpRequest getPTR = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/PTRRecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/PTRRecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -213,35 +218,35 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_ptr.json", APPLICATION_JSON)).build(); RecordId ptrId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("PTR") .id(50976579l).build(); public void testGetPTRWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getPTR, ptrResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getPTR(ptrId.getFQDN(), ptrId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getPTR(ptrId.getFQDN(), ptrId.getId()).toString(), new GetPTRRecordResponseTest().expected().toString()); } public void testGetPTRWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getPTR, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getPTR(ptrId.getFQDN(), ptrId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getPTR(ptrId.getFQDN(), ptrId.getId())); } public void testGetSOAWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getSOA, soaResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getSOA(soaId.getFQDN(), soaId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getSOA(soaId.getFQDN(), soaId.getId()).toString(), new GetSOARecordResponseTest().expected().toString()); } public void testGetSOAWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getSOA, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getSOA(soaId.getFQDN(), soaId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getSOA(soaId.getFQDN(), soaId.getId())); } HttpRequest getSRV = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/SRVRecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/SRVRecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -250,19 +255,19 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_srv.json", APPLICATION_JSON)).build(); RecordId srvId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("SRV") .id(50976579l).build(); public void testGetSRVWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getSRV, srvResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getSRV(srvId.getFQDN(), srvId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getSRV(srvId.getFQDN(), srvId.getId()).toString(), new GetSRVRecordResponseTest().expected().toString()); } HttpRequest getTXT = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/TXTRecord/adrianc.zone.dynecttest.jclouds.org/adrianc.zone.dynecttest.jclouds.org/50976579") + .endpoint("https://api2.dynect.net/REST/TXTRecord/jclouds.org/jclouds.org/50976579") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -271,24 +276,24 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { .payload(payloadFromResourceWithContentType("/get_record_txt.json", APPLICATION_JSON)).build(); RecordId txtId = recordIdBuilder() - .zone("adrianc.zone.dynecttest.jclouds.org") - .fqdn("adrianc.zone.dynecttest.jclouds.org") + .zone("jclouds.org") + .fqdn("jclouds.org") .type("TXT") .id(50976579l).build(); public void testGetTXTWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, getTXT, txtResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getTXT(txtId.getFQDN(), txtId.getId()).toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").getTXT(txtId.getFQDN(), txtId.getId()).toString(), new GetTXTRecordResponseTest().expected().toString()); } public void testGetTXTWhenResponseIs404() { DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, getTXT, notFound); - assertNull(fail.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").getTXT(txtId.getFQDN(), txtId.getId())); + assertNull(fail.getRecordApiForZone("jclouds.org").getTXT(txtId.getFQDN(), txtId.getId())); } HttpRequest list = HttpRequest.builder().method("GET") - .endpoint("https://api2.dynect.net/REST/AllRecord/adrianc.zone.dynecttest.jclouds.org") + .endpoint("https://api2.dynect.net/REST/AllRecord/jclouds.org") .addHeader("API-Version", "3.3.8") .addHeader(CONTENT_TYPE, APPLICATION_JSON) .addHeader("Auth-Token", authToken).build(); @@ -298,7 +303,69 @@ public class RecordApiExpectTest extends BaseDynECTApiExpectTest { public void testListWhenResponseIs2xx() { DynECTApi success = requestsSendResponses(createSession, createSessionResponse, list, listResponse); - assertEquals(success.getRecordApiForZone("adrianc.zone.dynecttest.jclouds.org").list().toString(), + assertEquals(success.getRecordApiForZone("jclouds.org").list().toString(), new ListRecordsResponseTest().expected().toString()); } + + HttpRequest listByFQDNAndType = HttpRequest.builder().method("GET") + .endpoint("https://api2.dynect.net/REST/ARecord/jclouds.org/www.foo.com") + .addHeader("API-Version", "3.3.8") + .addHeader(CONTENT_TYPE, APPLICATION_JSON) + .addHeader("Auth-Token", authToken).build(); + + public void testListByFQDNAndTypeWhenResponseIs2xx() { + DynECTApi success = requestsSendResponses(createSession, createSessionResponse, listByFQDNAndType, listResponse); + assertEquals(success.getRecordApiForZone("jclouds.org").listByFQDNAndType("www.foo.com", "A").toString(), + new ListRecordsResponseTest().expected().toString()); + } + + HttpRequest create = HttpRequest.builder().method("POST") + .endpoint("https://api2.dynect.net/REST/ARecord/jclouds.org/www.jclouds.org") + .addHeader("API-Version", "3.3.8") + .addHeader(ACCEPT, APPLICATION_JSON) + .addHeader("Auth-Token", authToken) + .payload(stringPayload("{\"rdata\":{\"address\":\"1.1.1.1\"},\"ttl\":86400}")) + .build(); + + HttpResponse createResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/new_record.json", APPLICATION_JSON)).build(); + + public void testCreateWhenResponseIs2xx() { + DynECTApi success = requestsSendResponses(createSession, createSessionResponse, create, createResponse); + CreateRecord record = CreateRecord. builder() + .fqdn("www.jclouds.org") + .type("A") + .ttl(86400) + .rdata(a("1.1.1.1")) + .build(); + assertEquals(success.getRecordApiForZone("jclouds.org").scheduleCreate(record), Job.success(285372440l)); + } + + HttpRequest delete = HttpRequest.builder().method("DELETE") + .endpoint("https://api2.dynect.net/REST/ARecord/jclouds.org/www.jclouds.org/285372440") + .addHeader("API-Version", "3.3.8") + .addHeader(ACCEPT, APPLICATION_JSON) + .addHeader(CONTENT_TYPE, APPLICATION_JSON) + .addHeader("Auth-Token", authToken).build(); + + HttpResponse deleteResponse = HttpResponse.builder().statusCode(200) + .payload(payloadFromResourceWithContentType("/delete_record.json", APPLICATION_JSON)).build(); + + RecordId id = recordIdBuilder() + .zone("jclouds.org") + .fqdn("www.jclouds.org") + .type("A") + .id(285372440l) + .build(); + + public void testDeleteWhenResponseIs2xx() { + DynECTApi success = requestsSendResponses(createSession, createSessionResponse, delete, deleteResponse); + + assertEquals(success.getRecordApiForZone("jclouds.org").scheduleDelete(id), Job.success(285372457l)); + } + + public void testDeleteWhenResponseIs404() { + DynECTApi fail = requestsSendResponses(createSession, createSessionResponse, delete, notFound); + assertNull(fail.getRecordApiForZone("jclouds.org").scheduleDelete(id)); + } } diff --git a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiLiveTest.java b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiLiveTest.java index 16fb2e25ce..9c58679472 100644 --- a/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiLiveTest.java +++ b/labs/dynect/src/test/java/org/jclouds/dynect/v3/features/RecordApiLiveTest.java @@ -20,14 +20,21 @@ package org.jclouds.dynect.v3.features; import static com.google.common.base.Preconditions.checkNotNull; import static java.util.logging.Logger.getAnonymousLogger; +import static org.jclouds.dynect.v3.domain.rdata.AData.a; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.util.Map; +import org.jclouds.JcloudsVersion; +import org.jclouds.dynect.v3.DynECTExceptions.JobStillRunningException; +import org.jclouds.dynect.v3.domain.CreateRecord; +import org.jclouds.dynect.v3.domain.Job; +import org.jclouds.dynect.v3.domain.Job.Status; import org.jclouds.dynect.v3.domain.Record; import org.jclouds.dynect.v3.domain.RecordId; import org.jclouds.dynect.v3.domain.SOARecord; +import org.jclouds.dynect.v3.domain.Zone; import org.jclouds.dynect.v3.domain.rdata.AAAAData; import org.jclouds.dynect.v3.domain.rdata.AData; import org.jclouds.dynect.v3.domain.rdata.CNAMEData; @@ -38,6 +45,7 @@ import org.jclouds.dynect.v3.domain.rdata.SOAData; import org.jclouds.dynect.v3.domain.rdata.SRVData; import org.jclouds.dynect.v3.domain.rdata.TXTData; import org.jclouds.dynect.v3.internal.BaseDynECTApiLiveTest; +import org.testng.annotations.AfterClass; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; @@ -64,8 +72,8 @@ public class RecordApiLiveTest extends BaseDynECTApiLiveTest { @Test protected void testListAndGetRecords() { - for (String zone : context.getApi().getZoneApi().list()) { - RecordApi api = context.getApi().getRecordApiForZone(zone); + for (String zone : zoneApi().list()) { + RecordApi api = api(zone); ImmutableList records = api.list().toList(); getAnonymousLogger().info("zone: " + zone + " record count: " + records.size()); @@ -162,4 +170,85 @@ public class RecordApiLiveTest extends BaseDynECTApiLiveTest { checkNotNull(rdata.getTxtdata(), "rdata.txtdata cannot be null for TXTRecord: %s", record); return record; } + + String zoneFQDN = System.getProperty("user.name").replace('.', '-') + ".record.dynecttest.jclouds.org"; + String contact = JcloudsVersion.get() + ".jclouds.org"; + + private void createZone() { + Job job = zoneApi().scheduleCreateWithContact(zoneFQDN, contact); + checkNotNull(job, "unable to create zone %s", zoneFQDN); + getAnonymousLogger().info("created zone: " + job); + assertEquals(job.getStatus(), Status.SUCCESS); + assertEquals(context.getApi().getJob(job.getId()), job); + Zone zone = zoneApi().publish(zoneFQDN); + checkNotNull(zone, "unable to publish zone %s", zoneFQDN); + getAnonymousLogger().info("published zone: " + zone); + } + + String fqdn = "www." + zoneFQDN; + CreateRecord record = CreateRecord. builder() + .fqdn("www." + zoneFQDN) + .type("A") + .ttl(86400) + .rdata(a("1.1.1.1")) + .build(); + + public void testCreateRecord() { + createZone(); + + Job job = null; + while (true) { + try { + job = api(zoneFQDN).scheduleCreate(record); + break; + } catch (JobStillRunningException e) { + continue; + } + } + + checkNotNull(job, "unable to create record %s", record); + getAnonymousLogger().info("created record: " + job); + assertEquals(job.getStatus(), Status.SUCCESS); + assertEquals(context.getApi().getJob(job.getId()), job); + zoneApi().publish(zoneFQDN); + } + + RecordId id; + + @Test(dependsOnMethods = "testCreateRecord") + public void testListByFQDNAndType() { + id = api(zoneFQDN).listByFQDNAndType(record.getFQDN(), record.getType()).toList().get(0); + getAnonymousLogger().info(id.toString()); + Record> newRecord = api(zoneFQDN).get(id); + assertEquals(newRecord.getFQDN(), record.getFQDN()); + assertEquals(newRecord.getType(), record.getType()); + assertEquals(newRecord.getTTL(), record.getTTL()); + assertEquals(newRecord.getRData(), record.getRData()); + checkRecord(newRecord); + } + + @Test(dependsOnMethods = "testListByFQDNAndType") + public void testDeleteRecord() { + Job job = api(zoneFQDN).scheduleDelete(id); + checkNotNull(job, "unable to delete record %s", id); + getAnonymousLogger().info("deleted record: " + job); + assertEquals(job.getStatus(), Status.SUCCESS); + assertEquals(context.getApi().getJob(job.getId()), job); + zoneApi().publish(zoneFQDN); + } + + protected RecordApi api(String zoneFQDN) { + return context.getApi().getRecordApiForZone(zoneFQDN); + } + + protected ZoneApi zoneApi() { + return context.getApi().getZoneApi(); + } + + @Override + @AfterClass(groups = "live", alwaysRun = true) + protected void tearDownContext() { + zoneApi().delete(zoneFQDN); + super.tearDownContext(); + } } diff --git a/labs/dynect/src/test/resources/delete_record.json b/labs/dynect/src/test/resources/delete_record.json new file mode 100644 index 0000000000..af0bf96c01 --- /dev/null +++ b/labs/dynect/src/test/resources/delete_record.json @@ -0,0 +1 @@ +{"status": "success", "data": {}, "job_id": 285372457, "msgs": [{"INFO": "delete: Record will be deleted on zone publish", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}, {"INFO": "remove_node: www.adriancole.zone.dynecttest.jclouds.org removed from tree.", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]} \ No newline at end of file diff --git a/labs/dynect/src/test/resources/new_record.json b/labs/dynect/src/test/resources/new_record.json new file mode 100644 index 0000000000..99a3c4979f --- /dev/null +++ b/labs/dynect/src/test/resources/new_record.json @@ -0,0 +1 @@ +{"status": "success", "data": {"zone": "adriancole.zone.dynecttest.jclouds.org", "ttl": 86400, "fqdn": "www.adriancole.zone.dynecttest.jclouds.org", "record_type": "A", "rdata": {"address": "1.1.1.1"}, "record_id": 0}, "job_id": 285372440, "msgs": [{"INFO": "add: Record added", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]} \ No newline at end of file diff --git a/labs/dynect/src/test/resources/new_zone.json b/labs/dynect/src/test/resources/new_zone.json new file mode 100644 index 0000000000..1fbbafb784 --- /dev/null +++ b/labs/dynect/src/test/resources/new_zone.json @@ -0,0 +1 @@ +{"status": "success", "data": {"zone_type": "Primary", "serial_style": "increment", "serial": 0, "zone": "adriancole.zone.dynecttest.jclouds.org"}, "job_id": 285351593, "msgs": [{"INFO": "create: New zone adriancole.zone.dynecttest.jclouds.org created. Publish it to put it on our server.", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}, {"INFO": "setup: If you plan to provide your own secondary DNS for the zone, allow notify requests from these IP addresses on your nameserver: 204.13.249.66, 208.78.68.66, 2600:2001:0:1::66, 2600:2003:0:1::66", "SOURCE": "BLL", "ERR_CD": null, "LVL": "INFO"}]} \ No newline at end of file