From b75652e1d1519d6f015c890384fc6dcd89d8affe Mon Sep 17 00:00:00 2001 From: Martin Derka Date: Fri, 15 Apr 2016 16:04:23 -0400 Subject: [PATCH] Added batch support to the local DNS helper. (#925) Added batch support to the local DNS helper --- gcloud-java-dns/pom.xml | 5 + .../cloud/dns/testing/LocalDnsHelper.java | 110 +- .../cloud/dns/testing/LocalDnsHelperTest.java | 1075 ++++++++++++++++- 3 files changed, 1184 insertions(+), 6 deletions(-) diff --git a/gcloud-java-dns/pom.xml b/gcloud-java-dns/pom.xml index 73e949dd5b1e..8acd6abee783 100644 --- a/gcloud-java-dns/pom.xml +++ b/gcloud-java-dns/pom.xml @@ -40,6 +40,11 @@ + + commons-fileupload + commons-fileupload + 1.3.1 + ${project.groupId} gcloud-java-core diff --git a/gcloud-java-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java b/gcloud-java-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java index 1f35193409ee..14632869f6ba 100644 --- a/gcloud-java-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java +++ b/gcloud-java-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java @@ -20,6 +20,7 @@ import static java.net.HttpURLConnection.HTTP_NO_CONTENT; import static java.net.HttpURLConnection.HTTP_OK; +import com.google.api.client.http.HttpMediaType; import com.google.api.client.json.JsonFactory; import com.google.api.client.json.jackson.JacksonFactory; import com.google.api.services.dns.model.Change; @@ -43,13 +44,16 @@ import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; +import org.apache.commons.fileupload.MultipartStream; import org.joda.time.format.ISODateTimeFormat; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.net.InetSocketAddress; +import java.net.Socket; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; @@ -62,6 +66,7 @@ import java.util.NavigableMap; import java.util.NavigableSet; import java.util.Random; +import java.util.Scanner; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; @@ -112,6 +117,9 @@ public class LocalDnsHelper { private static final ScheduledExecutorService EXECUTORS = Executors.newScheduledThreadPool(2, Executors.defaultThreadFactory()); private static final String PROJECT_ID = "dummyprojectid"; + private static final String RESPONSE_BOUNDARY = "____THIS_IS_HELPERS_BOUNDARY____"; + private static final String RESPONSE_SEPARATOR = "--" + RESPONSE_BOUNDARY + "\r\n"; + private static final String RESPONSE_END = "--" + RESPONSE_BOUNDARY + "--\r\n\r\n"; static { try { @@ -138,7 +146,8 @@ private enum CallRegex { ZONE_GET("GET", CONTEXT + "/[^/]+/managedZones/[^/]+"), ZONE_LIST("GET", CONTEXT + "/[^/]+/managedZones"), PROJECT_GET("GET", CONTEXT + "/[^/]+"), - RECORD_LIST("GET", CONTEXT + "/[^/]+/managedZones/[^/]+/rrsets"); + RECORD_LIST("GET", CONTEXT + "/[^/]+/managedZones/[^/]+/rrsets"), + BATCH("POST", "/batch"); private final String method; private final String pathRegex; @@ -273,13 +282,18 @@ private String toJson(String message) throws IOException { private class RequestHandler implements HttpHandler { private Response pickHandler(HttpExchange exchange, CallRegex regex) { - URI relative = BASE_CONTEXT.relativize(exchange.getRequestURI()); + URI relative = null; + try { + relative = BASE_CONTEXT.relativize(new URI(exchange.getRequestURI().getRawPath())); + } catch (URISyntaxException e) { + return Error.INTERNAL_ERROR.response("Parsing URI failed."); + } String path = relative.getPath(); String[] tokens = path.split("/"); String projectId = tokens.length > 0 ? tokens[0] : null; String zoneName = tokens.length > 2 ? tokens[2] : null; String changeId = tokens.length > 4 ? tokens[4] : null; - String query = relative.getQuery(); + String query = exchange.getRequestURI().getQuery(); switch (regex) { case CHANGE_GET: return getChange(projectId, zoneName, changeId, query); @@ -307,6 +321,12 @@ private Response pickHandler(HttpExchange exchange, CallRegex regex) { } catch (IOException ex) { return Error.BAD_REQUEST.response(ex.getMessage()); } + case BATCH: + try { + return handleBatch(exchange); + } catch (IOException ex) { + return Error.BAD_REQUEST.response(ex.getMessage()); + } default: return Error.INTERNAL_ERROR.response("Operation without a handler."); } @@ -319,7 +339,11 @@ public void handle(HttpExchange exchange) throws IOException { for (CallRegex regex : CallRegex.values()) { if (requestMethod.equals(regex.method) && rawPath.matches(regex.pathRegex)) { Response response = pickHandler(exchange, regex); - writeResponse(exchange, response); + if (response != null) { + /* null response is returned by batch request, because it handles writing + the response on its own */ + writeResponse(exchange, response); + } return; } } @@ -328,6 +352,67 @@ public void handle(HttpExchange exchange) throws IOException { requestMethod, exchange.getRequestURI()))); } + private Response handleBatch(final HttpExchange exchange) throws IOException { + String contentType = exchange.getRequestHeaders().getFirst("Content-type"); + if (contentType != null) { + int port = server.getAddress().getPort(); + HttpMediaType httpMediaType = new HttpMediaType(contentType); + String boundary = httpMediaType.getParameter("boundary"); + MultipartStream multipartStream = + new MultipartStream(exchange.getRequestBody(), boundary.getBytes(), 1024, null); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] bytes = new byte[1024]; + multipartStream.skipPreamble(); + while (multipartStream.readBoundary()) { + Socket socket = new Socket("localhost", port); + OutputStream socketOutput = socket.getOutputStream(); + ByteArrayOutputStream section = new ByteArrayOutputStream(); + multipartStream.readBodyData(section); + String line; + String contentId = null; + Scanner scanner = new Scanner(new String(section.toByteArray())); + while (scanner.hasNextLine()) { + line = scanner.nextLine(); + if(line.isEmpty()) { + break; + } else if (line.toLowerCase().startsWith("content-id")) { + contentId = line.split(":")[1].trim(); + } + } + String requestLine = scanner.nextLine(); + socketOutput.write((requestLine + " \r\n").getBytes()); + socketOutput.write("Connection: close \r\n".getBytes()); + while(scanner.hasNextLine()) { + line = scanner.nextLine(); + socketOutput.write(line.getBytes()); + if (!line.isEmpty()) { + socketOutput.write(" \r\n".getBytes()); + } else { + socketOutput.write("\r\n".getBytes()); + } + } + socketOutput.flush(); + InputStream in = socket.getInputStream(); + int length; + out.write(RESPONSE_SEPARATOR.getBytes()); + out.write("Content-Type: application/http \r\n".getBytes()); + out.write(("Content-ID: " + contentId + " \r\n\r\n").getBytes()); + try { + while ((length = in.read(bytes)) != -1) { + out.write(bytes, 0, length); + } + } catch (IOException ex) { + // this handles connection reset error + } + } + out.write(RESPONSE_END.getBytes()); + writeBatchResponse(exchange, out); + } else { + return Error.BAD_REQUEST.response("Content-type header was not provided for batch."); + } + return null; + } + /** * @throws IOException if the request cannot be parsed. */ @@ -368,7 +453,8 @@ private LocalDnsHelper(long delay) { try { server = HttpServer.create(new InetSocketAddress(0), 0); port = server.getAddress().getPort(); - server.createContext(CONTEXT, new RequestHandler()); + server.setExecutor(Executors.newCachedThreadPool()); + server.createContext("/", new RequestHandler()); } catch (IOException e) { throw new RuntimeException("Could not bind the mock DNS server.", e); } @@ -430,6 +516,20 @@ private static void writeResponse(HttpExchange exchange, Response response) { } } + private static void writeBatchResponse(HttpExchange exchange, ByteArrayOutputStream output) { + exchange.getResponseHeaders().set( + "Content-type", "multipart/mixed; boundary=" + RESPONSE_BOUNDARY); + try { + exchange.getResponseHeaders().add("Connection", "close"); + exchange.sendResponseHeaders(200, output.toByteArray().length); + OutputStream responseBody = exchange.getResponseBody(); + output.writeTo(responseBody); + responseBody.close(); + } catch (IOException e) { + log.log(Level.WARNING, "IOException encountered when sending response.", e); + } + } + private static String decodeContent(Headers headers, InputStream inputStream) throws IOException { List contentEncoding = headers.get("Content-encoding"); InputStream input = inputStream; diff --git a/gcloud-java-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java b/gcloud-java-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java index fce958d3a126..6ac28df7c132 100644 --- a/gcloud-java-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java +++ b/gcloud-java-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java @@ -23,16 +23,22 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.google.api.client.googleapis.json.GoogleJsonError; import com.google.api.services.dns.model.Change; +import com.google.api.services.dns.model.ChangesListResponse; import com.google.api.services.dns.model.ManagedZone; +import com.google.api.services.dns.model.ManagedZonesListResponse; import com.google.api.services.dns.model.Project; import com.google.api.services.dns.model.ResourceRecordSet; +import com.google.api.services.dns.model.ResourceRecordSetsListResponse; import com.google.cloud.dns.DnsException; import com.google.cloud.dns.spi.DefaultDnsRpc; import com.google.cloud.dns.spi.DnsRpc; +import com.google.cloud.dns.spi.RpcBatch; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import org.junit.AfterClass; @@ -72,6 +78,24 @@ public class LocalDnsHelperTest { private static final String REAL_PROJECT_ID = LOCAL_DNS_HELPER.options().projectId(); private Map optionsMap; + private static abstract class FailExpectedCallback implements RpcBatch.Callback { + @Override + public void onSuccess(T t) { + fail(); + } + + public abstract void onFailure(GoogleJsonError e); + } + + private static abstract class SuccessExpectedCallback implements RpcBatch.Callback { + public abstract void onSuccess(T t); + + @Override + public void onFailure(GoogleJsonError e) { + fail(); + } + } + @BeforeClass public static void before() { ZONE1.setName(ZONE_NAME1); @@ -682,7 +706,7 @@ public void testListZones() { } @Test - public void testListDnsRecords() { + public void testListRecordSets() { // no zone exists try { RPC.listRecordSets(ZONE_NAME1, EMPTY_RPC_OPTIONS); @@ -1445,4 +1469,1053 @@ private static ResourceRecordSet copyRrset(ResourceRecordSet set) { copy.setType(set.getType()); return copy; } + + @Test + public void testGetProjectBatch() { + // the projects are automatically created when getProject is called + assertNotNull(LOCAL_DNS_HELPER.getProject(PROJECT_ID1, null)); + assertNotNull(LOCAL_DNS_HELPER.getProject(PROJECT_ID2, null)); + RpcBatch batch = RPC.createBatch(); + batch.addGetProject(new SuccessExpectedCallback() { + @Override + public void onSuccess(Project project) { + assertNotNull(project.getQuota()); + assertEquals(REAL_PROJECT_ID, project.getId()); + } + }, EMPTY_RPC_OPTIONS); + batch.addGetProject(new SuccessExpectedCallback() { + @Override + public void onSuccess(Project project) { + assertNull(project.getId()); + assertNotNull(project.getNumber()); + assertNull(project.getQuota()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "number")); + batch.addGetProject(new SuccessExpectedCallback() { + @Override + public void onSuccess(Project project) { + assertNotNull(project.getId()); + assertNull(project.getNumber()); + assertNull(project.getQuota()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "id")); + batch.addGetProject(new SuccessExpectedCallback() { + @Override + public void onSuccess(Project project) { + assertNull(project.getId()); + assertNull(project.getNumber()); + assertNotNull(project.getQuota()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "quota")); + batch.submit(); + } + + @Test + public void testCreateZoneBatch() { + RpcBatch batch = RPC.createBatch(); + batch.addCreateZone(ZONE1, new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone created) { + // check that default records were created + DnsRpc.ListResult listResult + = RPC.listRecordSets(ZONE1.getName(), EMPTY_RPC_OPTIONS); + ImmutableList defaultTypes = ImmutableList.of("SOA", "NS"); + Iterator iterator = listResult.results().iterator(); + assertTrue(defaultTypes.contains(iterator.next().getType())); + assertTrue(defaultTypes.contains(iterator.next().getType())); + assertFalse(iterator.hasNext()); + assertEquals(created, LOCAL_DNS_HELPER.findZone(REAL_PROJECT_ID, ZONE1.getName()).zone()); + ManagedZone zone = RPC.getZone(ZONE_NAME1, EMPTY_RPC_OPTIONS); + assertEquals(created, zone); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + batch = RPC.createBatch(); + batch.addCreateZone(null, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError googleJsonError) { + assertEquals(400, googleJsonError.getCode()); + assertTrue(googleJsonError.getMessage().contains("entity.managedZone")); + } + }, EMPTY_RPC_OPTIONS); + batch.addCreateZone(ZONE1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + assertEquals(409, ex.getCode()); + assertTrue(ex.getMessage().contains("already exists")); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // field options + resetProjects(); + batch = RPC.createBatch(); + batch.addCreateZone(copyZoneNewName(ZONE1, "z1"), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNotNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "id")); + batch.addCreateZone(copyZoneNewName(ZONE1, "z2"), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNotNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "creationTime")); + batch.addCreateZone(copyZoneNewName(ZONE1, "z3"), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNotNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "dnsName")); + batch.addCreateZone(copyZoneNewName(ZONE1, "z4"), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNotNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "description")); + batch.addCreateZone(copyZoneNewName(ZONE1, "z5"), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNotNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nameServers")); + batch.addCreateZone(copyZoneNewName(ZONE1, "z6"), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNotNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nameServerSet")); + batch.addCreateZone(copyZoneNewName(ZONE1, "z7"), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNotNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNotNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNotNull(zone.getNameServerSet()); + assertNotNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nameServerSet,description,id,name")); + batch.submit(); + } + + @Test + public void testGetZoneBatch() { + // non-existent + assertNull(RPC.getZone(ZONE_NAME1, EMPTY_RPC_OPTIONS)); + // existent + final ManagedZone created = RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + ManagedZone zone = RPC.getZone(ZONE_NAME1, EMPTY_RPC_OPTIONS); + assertEquals(created, zone); + assertEquals(ZONE1.getName(), zone.getName()); + // field options + RpcBatch batch = RPC.createBatch(); + batch.addGetZone(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertEquals(created.getId(), zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "id")); + batch.addGetZone(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertEquals(created.getCreationTime(), zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "creationTime")); + batch.addGetZone(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertEquals(created.getDnsName(), zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "dnsName")); + batch.addGetZone(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertEquals(created.getDescription(), zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "description")); + batch.addGetZone(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertEquals(created.getNameServers(), zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nameServers")); + batch.addGetZone(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertEquals(created.getNameServerSet(), zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nameServerSet")); + batch.addGetZone(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone zone) { + assertNull(zone.getCreationTime()); + assertEquals(created.getName(), zone.getName()); + assertNull(zone.getDnsName()); + assertEquals(created.getDescription(), zone.getDescription()); + assertNull(zone.getNameServers()); + assertEquals(created.getNameServerSet(), zone.getNameServerSet()); + assertEquals(created.getId(), zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nameServerSet,description,id,name")); + batch.submit(); + } + + @Test + public void testDeleteZoneBatch() { + RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + RpcBatch batch = RPC.createBatch(); + batch.addDeleteZone(ZONE1.getName(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Void response) { + assertNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); + } + }); + batch.submit(); + batch = RPC.createBatch(); + assertNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); + // deleting non-existent zone + batch.addDeleteZone(ZONE1.getName(), new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(404, ex.getCode()); + } + }); + batch.submit(); + RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + RPC.create(ZONE2, EMPTY_RPC_OPTIONS); + assertNotNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); + assertNotNull(RPC.getZone(ZONE2.getName(), EMPTY_RPC_OPTIONS)); + // delete mutiple + batch = RPC.createBatch(); + batch.addDeleteZone(ZONE2.getName(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Void response) { + assertNull(RPC.getZone(ZONE2.getName(), EMPTY_RPC_OPTIONS)); + } + }); + batch.addDeleteZone(ZONE1.getName(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Void response) { + assertNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); + } + }); + batch.submit(); + RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + RPC.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); + batch = RPC.createBatch(); + batch.addDeleteZone(ZONE1.getName(), new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("not empty")); + } + }); + batch.submit(); + } + + private static ManagedZone copyZoneNewName(ManagedZone zone, String name) { + ManagedZone copy = new ManagedZone(); + for (String key : zone.keySet()) { + copy.set(key, zone.get(key)); + } + copy.setName(name); + return copy; + } + + @Test + public void testListZonesBatch() { + RpcBatch batch = RPC.createBatch(); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse zones) { + assertEquals(0, zones.getManagedZones().size()); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // some zones exists + + final ManagedZone first = RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + final ManagedZone second = RPC.create(ZONE2, EMPTY_RPC_OPTIONS); + batch = RPC.createBatch(); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse zones) { + List results = zones.getManagedZones(); + assertEquals(2, results.size()); + assertTrue(results.contains(first)); + assertTrue(results.contains(second)); + } + }, EMPTY_RPC_OPTIONS); + // error in options + batch.addListZones(new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.maxResults")); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, 0)); + batch.addListZones(new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.maxResults")); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, -1)); + // ok size + batch.addListZones(new RpcBatch.Callback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + assertEquals(1, response.getManagedZones().size()); + } + + @Override + public void onFailure(GoogleJsonError ex) { + fail(); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, 1)); + // dns name problems + batch.addListZones(new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.dnsName")); + } + }, ImmutableMap.of(DnsRpc.Option.DNS_NAME, "aaa")); + // ok name + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + assertEquals(0, response.getManagedZones().size()); + } + }, ImmutableMap.of(DnsRpc.Option.DNS_NAME, "aaaa.")); + // field options + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + ManagedZone zone = response.getManagedZones().get(0); + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNotNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "managedZones(id)")); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + ManagedZone zone = response.getManagedZones().get(0); + assertNotNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "managedZones(creationTime)")); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + ManagedZone zone = response.getManagedZones().get(0); + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNotNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "managedZones(dnsName)")); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + ManagedZone zone = response.getManagedZones().get(0); + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNotNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "managedZones(description)")); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + ManagedZone zone = response.getManagedZones().get(0); + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNotNull(zone.getNameServers()); + assertNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "managedZones(nameServers)")); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + ManagedZone zone = response.getManagedZones().get(0); + assertNull(response.getNextPageToken()); + assertNull(zone.getCreationTime()); + assertNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNotNull(zone.getNameServerSet()); + assertNull(zone.getId()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "managedZones(nameServerSet)")); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + ManagedZone zone = response.getManagedZones().get(0); + assertNull(zone.getCreationTime()); + assertNotNull(zone.getName()); + assertNull(zone.getDnsName()); + assertNotNull(zone.getDescription()); + assertNull(zone.getNameServers()); + assertNotNull(zone.getNameServerSet()); + assertNotNull(zone.getId()); + assertEquals(zone.getName(), response.getNextPageToken()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, + "managedZones(nameServerSet,description,id,name),nextPageToken", + DnsRpc.Option.PAGE_SIZE, 1)); + batch.submit(); + } + + @Test + public void testListRecordSetsBatch() { + // no zone exists + RpcBatch batch = RPC.createBatch(); + batch.addListRecordSets(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(404, ex.getCode()); + assertTrue(ex.getMessage().contains("managedZone")); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // zone exists but has no records + batch = RPC.createBatch(); + RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + assertEquals(2, response.getRrsets().size()); // contains default NS and SOA + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // zone has records + RPC.applyChangeRequest(ZONE_NAME1, CHANGE_KEEP, EMPTY_RPC_OPTIONS); + batch = RPC.createBatch(); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + assertEquals(3, response.getRrsets().size()); + } + }, EMPTY_RPC_OPTIONS); + batch.addListRecordSets(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.maxResults")); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, 0)); + batch.addListRecordSets(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.maxResults")); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, -1)); + // ok size + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + assertEquals(2, response.getRrsets().size()); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, 2)); + // dns name filter + batch.addListRecordSets(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.name")); + } + }, ImmutableMap.of(DnsRpc.Option.NAME, "aaa")); + // dns name filter + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + assertEquals(0, response.getRrsets().size()); + } + }, ImmutableMap.of(DnsRpc.Option.NAME, "aaa.")); + // filter type but no name + batch.addListRecordSets(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.name")); + } + }, ImmutableMap.of(DnsRpc.Option.DNS_TYPE, "A")); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + assertEquals(1, response.getRrsets().size()); + } + }, ImmutableMap.of(DnsRpc.Option.NAME, ZONE1.getDnsName(), DnsRpc.Option.DNS_TYPE, "SOA")); + // field options + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + ResourceRecordSet record = response.getRrsets().get(0); + assertNotNull(record.getName()); + assertNull(record.getRrdatas()); + assertNull(record.getType()); + assertNull(record.getTtl()); + assertNull(response.getNextPageToken()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "rrsets(name)")); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + ResourceRecordSet record = response.getRrsets().get(0); + assertNull(record.getName()); + assertNotNull(record.getRrdatas()); + assertNull(record.getType()); + assertNull(record.getTtl()); + assertNull(response.getNextPageToken()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "rrsets(rrdatas)")); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + ResourceRecordSet record = response.getRrsets().get(0); + assertNull(record.getName()); + assertNull(record.getRrdatas()); + assertNull(record.getType()); + assertNotNull(record.getTtl()); + assertNull(response.getNextPageToken()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "rrsets(ttl)")); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + ResourceRecordSet record = response.getRrsets().get(0); + assertNull(record.getName()); + assertNull(record.getRrdatas()); + assertNotNull(record.getType()); + assertNull(record.getTtl()); + assertNull(response.getNextPageToken()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "rrsets(type)")); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + ResourceRecordSet record = response.getRrsets().get(0); + assertNull(record.getName()); + assertNull(record.getRrdatas()); + assertNull(record.getType()); + assertNull(record.getTtl()); + assertNull(response.getNextPageToken()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nextPageToken")); + batch.addListRecordSets(ZONE_NAME1, + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + assertEquals(1, response.getRrsets().size()); + ResourceRecordSet record = response.getRrsets().get(0); + assertNotNull(record.getName()); + assertNotNull(record.getRrdatas()); + assertNull(record.getType()); + assertNull(record.getTtl()); + assertNotNull(response.getNextPageToken()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "nextPageToken,rrsets(name,rrdatas)", + DnsRpc.Option.PAGE_SIZE, 1)); + batch.submit(); + } + + @Test + public void testCreateChangeBatch() { + // non-existent zone + RpcBatch batch = RPC.createBatch(); + batch.addApplyChangeRequest(ZONE_NAME1, CHANGE1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(404, ex.getCode()); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // existent zone + RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + assertNull(RPC.getChangeRequest(ZONE_NAME1, "1", EMPTY_RPC_OPTIONS)); + batch = RPC.createBatch(); + batch.addApplyChangeRequest(ZONE_NAME1, CHANGE1, new SuccessExpectedCallback() { + @Override + public void onSuccess(Change response) { + assertEquals(RPC.getChangeRequest(ZONE_NAME1, "1", EMPTY_RPC_OPTIONS), response); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // field options + RPC.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); + batch = RPC.createBatch(); + batch.addApplyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, + new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNotNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "additions")); + batch.addApplyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, + new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNotNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "deletions")); + batch.addApplyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, + new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNotNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "id")); + batch.addApplyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, + new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNotNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "startTime")); + batch.addApplyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, + new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNotNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "status")); + batch.submit(); + } + + @Test + public void testGetChangeBatch() { + // existent + RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + final Change created = RPC.applyChangeRequest(ZONE1.getName(), CHANGE1, EMPTY_RPC_OPTIONS); + RpcBatch batch = RPC.createBatch(); + batch.addGetChangeRequest(ZONE1.getName(), "1", new SuccessExpectedCallback() { + @Override + public void onSuccess(Change retrieved) { + assertEquals(created, retrieved); + } + }, EMPTY_RPC_OPTIONS); + // non-existent + batch.addGetChangeRequest(ZONE1.getName(), "2", new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError googleJsonError) { + // expected + assertEquals(404, googleJsonError.getCode()); + } + }, EMPTY_RPC_OPTIONS); + // non-existent zone + batch.addGetChangeRequest(ZONE_NAME2, "1", new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(404, ex.getCode()); + assertTrue(ex.getMessage().contains("managedZone")); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // field options + RPC.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); + Change keep = RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, EMPTY_RPC_OPTIONS); + batch = RPC.createBatch(); + batch.addGetChangeRequest(ZONE1.getName(), keep.getId(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNotNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "additions")); + batch.addGetChangeRequest(ZONE1.getName(), keep.getId(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNotNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "deletions")); + batch.addGetChangeRequest(ZONE1.getName(), keep.getId(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNotNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "id")); + batch.addGetChangeRequest(ZONE1.getName(), keep.getId(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNotNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "startTime")); + batch.addGetChangeRequest(ZONE1.getName(), keep.getId(), new SuccessExpectedCallback() { + @Override + public void onSuccess(Change complex) { + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNotNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "status")); + batch.submit(); + } + + @Test + public void testListChangesBatch() { + RpcBatch batch = RPC.createBatch(); + batch.addListChangeRequests(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(404, ex.getCode()); + assertTrue(ex.getMessage().contains("managedZone")); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + + // zone exists but has no changes bu the default + batch = RPC.createBatch(); + RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + batch.addListChangeRequests(ZONE_NAME1, new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + assertEquals(1, response.getChanges().size()); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + // zone has changes + RPC.applyChangeRequest(ZONE1.getName(), CHANGE1, EMPTY_RPC_OPTIONS); + RPC.applyChangeRequest(ZONE1.getName(), CHANGE2, EMPTY_RPC_OPTIONS); + RPC.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); + batch = RPC.createBatch(); + batch.addListChangeRequests(ZONE_NAME1, new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + assertEquals(4, response.getChanges().size()); + } + }, EMPTY_RPC_OPTIONS); + // error in options + batch.addListChangeRequests(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.maxResults")); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, 0)); + batch.addListChangeRequests(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.maxResults")); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, -1)); + // ok size + batch.addListChangeRequests(ZONE_NAME1, new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + assertEquals(2, response.getChanges().size()); + } + }, ImmutableMap.of(DnsRpc.Option.PAGE_SIZE, 2)); + final Iterable descending = RPC.listChangeRequests(ZONE1.getName(), + ImmutableMap.of(DnsRpc.Option.SORTING_ORDER, "descending")).results(); + final int size = 4; + batch.addListChangeRequests(ZONE_NAME1, new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + List changes = response.getChanges(); + for (int i = 0; i < size; i++) { + assertEquals(Iterables.get(descending, i), changes.get(i)); + } + } + }, ImmutableMap.of(DnsRpc.Option.SORTING_ORDER, "descending")); + batch.addListChangeRequests(ZONE_NAME1, new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + List changes = response.getChanges(); + for (int i = 0; i < size; i++) { + assertEquals(Iterables.get(descending, i), changes.get(size - i - 1)); + } + } + }, ImmutableMap.of(DnsRpc.Option.SORTING_ORDER, "ascending")); + batch.addListChangeRequests(ZONE_NAME1, new FailExpectedCallback() { + @Override + public void onFailure(GoogleJsonError ex) { + // expected + assertEquals(400, ex.getCode()); + assertTrue(ex.getMessage().contains("parameters.sortOrder")); + } + }, ImmutableMap.of(DnsRpc.Option.SORTING_ORDER, "something else")); + batch.submit(); + // field options + batch = RPC.createBatch(); + RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, EMPTY_RPC_OPTIONS); + batch.addListChangeRequests(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + Change complex = response.getChanges().get(0); + assertNotNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "additions", + DnsRpc.Option.SORTING_ORDER, "descending")); + batch.addListChangeRequests(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + Change complex = response.getChanges().get(0); + assertNull(complex.getAdditions()); + assertNotNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "deletions", + DnsRpc.Option.SORTING_ORDER, "descending")); + batch.addListChangeRequests(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + Change complex = response.getChanges().get(0); + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNotNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "id", + DnsRpc.Option.SORTING_ORDER, "descending")); + batch.addListChangeRequests(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + Change complex = response.getChanges().get(0); + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNotNull(complex.getStartTime()); + assertNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "startTime", + DnsRpc.Option.SORTING_ORDER, "descending")); + batch.addListChangeRequests(ZONE1.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + Change complex = response.getChanges().get(0); + assertNull(complex.getAdditions()); + assertNull(complex.getDeletions()); + assertNull(complex.getId()); + assertNull(complex.getStartTime()); + assertNotNull(complex.getStatus()); + } + }, ImmutableMap.of(DnsRpc.Option.FIELDS, "status", + DnsRpc.Option.SORTING_ORDER, "descending")); + batch.submit(); + } + + @Test + public void testCombined() { + final ManagedZone created = RPC.create(ZONE1, EMPTY_RPC_OPTIONS); + RpcBatch batch = RPC.createBatch(); + batch.addListZones(new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZonesListResponse response) { + assertEquals(1, response.getManagedZones().size()); + assertEquals(created, response.getManagedZones().get(0)); + } + }, EMPTY_RPC_OPTIONS); + batch.addGetZone(created.getName(), new SuccessExpectedCallback() { + @Override + public void onSuccess(ManagedZone response) { + assertEquals(created, response); + } + }, EMPTY_RPC_OPTIONS); + batch.addListChangeRequests(created.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ChangesListResponse response) { + assertEquals(1, response.getChanges().size()); + assertEquals(RPC.getChangeRequest(created.getName(), "0", EMPTY_RPC_OPTIONS), + response.getChanges().get(0)); + } + }, EMPTY_RPC_OPTIONS); + batch.addListRecordSets(created.getName(), + new SuccessExpectedCallback() { + @Override + public void onSuccess(ResourceRecordSetsListResponse response) { + assertEquals(2, response.getRrsets().size()); + } + }, EMPTY_RPC_OPTIONS); + batch.addGetChangeRequest(created.getName(), "0", new SuccessExpectedCallback() { + @Override + public void onSuccess(Change response) { + assertEquals(RPC.getChangeRequest(created.getName(), "0", EMPTY_RPC_OPTIONS), response); + } + }, EMPTY_RPC_OPTIONS); + batch.submit(); + } }