From 7efcda6b741ec5460a3ab9852bf8297289aaf5ff Mon Sep 17 00:00:00 2001 From: Michael Darakananda Date: Tue, 6 Dec 2016 10:32:16 +1100 Subject: [PATCH] nuke LocalDnsHelper The emulator is a frequent source of test failures and not used anywhere useful. --- .../cloud/dns/testing/LocalDnsHelper.java | 1391 --------- .../cloud/dns/testing/OptionParsers.java | 258 -- .../cloud/dns/testing/package-info.java | 36 - .../cloud/dns/testing/LocalDnsHelperTest.java | 2520 ----------------- 4 files changed, 4205 deletions(-) delete mode 100644 google-cloud-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java delete mode 100644 google-cloud-dns/src/main/java/com/google/cloud/dns/testing/OptionParsers.java delete mode 100644 google-cloud-dns/src/main/java/com/google/cloud/dns/testing/package-info.java delete mode 100644 google-cloud-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java diff --git a/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java b/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java deleted file mode 100644 index 4d7fb277c388..000000000000 --- a/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/LocalDnsHelper.java +++ /dev/null @@ -1,1391 +0,0 @@ -/* - * Copyright 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.cloud.dns.testing; - -import static com.google.common.net.InetAddresses.isInetAddress; -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; -import com.google.api.services.dns.model.ManagedZone; -import com.google.api.services.dns.model.Project; -import com.google.api.services.dns.model.Quota; -import com.google.api.services.dns.model.ResourceRecordSet; -import com.google.cloud.NoCredentials; -import com.google.cloud.dns.DnsOptions; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.ImmutableSortedMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.google.common.io.ByteStreams; - -import com.sun.net.httpserver.Headers; -import com.sun.net.httpserver.HttpExchange; -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; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -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; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ConcurrentNavigableMap; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Pattern; -import java.util.zip.GZIPInputStream; - -/** - * A local Google Cloud DNS mock. - * - *

The mock runs in a separate thread, listening for HTTP requests on the local machine at an - * ephemeral port. - * - *

While the mock attempts to simulate the service, there are some differences in the behaviour. - * The mock will accept any project ID and never returns a notFound or another error because of - * project ID. It assumes that all project IDs exist and that the user has all the necessary - * privileges to manipulate any project. Similarly, the local simulation does not require - * verification of domain name ownership. Any request for creating a managed zone will be approved. - * The mock does not track quota and will allow the user to exceed it. The mock provides only basic - * validation of the DNS data for record sets of type A and AAAA. It does not validate any other - * record set types. - */ -public class LocalDnsHelper { - - private final ConcurrentSkipListMap projects - = new ConcurrentSkipListMap<>(); - private static final URI BASE_CONTEXT; - private static final Logger log = Logger.getLogger(LocalDnsHelper.class.getName()); - private static final JsonFactory jsonFactory = new JacksonFactory(); - private static final Random ID_GENERATOR = new Random(); - private static final String VERSION = "v1"; - private static final String CONTEXT = "/dns/" + VERSION + "/projects"; - private static final Set ENCODINGS = ImmutableSet.of("gzip", "x-gzip"); - private static final List TYPES = ImmutableList.of("A", "AAAA", "CNAME", "MX", "NAPTR", - "NS", "PTR", "SOA", "SPF", "SRV", "TXT"); - private static final TreeSet FORBIDDEN = Sets.newTreeSet( - ImmutableList.of("google.com.", "com.", "example.com.", "net.", "org.")); - private static final Pattern ZONE_NAME_RE = Pattern.compile("[a-z][a-z0-9-]*"); - 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 { - BASE_CONTEXT = new URI(CONTEXT); - } catch (URISyntaxException e) { - throw new IllegalArgumentException( - "Could not initialize LocalDnsHelper due to URISyntaxException.", e); - } - } - - private final long delayChange; - private final HttpServer server; - private final int port; - - /** - * For matching URLs to operations. - */ - private enum CallRegex { - CHANGE_CREATE("POST", CONTEXT + "/[^/]+/managedZones/[^/]+/changes"), - CHANGE_GET("GET", CONTEXT + "/[^/]+/managedZones/[^/]+/changes/[^/]+"), - CHANGE_LIST("GET", CONTEXT + "/[^/]+/managedZones/[^/]+/changes"), - ZONE_CREATE("POST", CONTEXT + "/[^/]+/managedZones"), - ZONE_DELETE("DELETE", CONTEXT + "/[^/]+/managedZones/[^/]+"), - ZONE_GET("GET", CONTEXT + "/[^/]+/managedZones/[^/]+"), - ZONE_LIST("GET", CONTEXT + "/[^/]+/managedZones"), - PROJECT_GET("GET", CONTEXT + "/[^/]+"), - RECORD_LIST("GET", CONTEXT + "/[^/]+/managedZones/[^/]+/rrsets"), - BATCH("POST", "/batch"); - - private final String method; - private final String pathRegex; - - CallRegex(String method, String pathRegex) { - this.pathRegex = pathRegex; - this.method = method; - } - } - - /** - * Associates a project with a collection of ManagedZones. - */ - static class ProjectContainer { - private final Project project; - private final ConcurrentSkipListMap zones = - new ConcurrentSkipListMap<>(); - - ProjectContainer(Project project) { - this.project = project; - } - - Project project() { - return project; - } - - ConcurrentSkipListMap zones() { - return zones; - } - } - - /** - * Associates a zone with a collection of changes and dns records. - */ - static class ZoneContainer { - private final ManagedZone zone; - private final AtomicReference> - dnsRecords = new AtomicReference<>(ImmutableSortedMap.of()); - private final ConcurrentLinkedQueue changes = new ConcurrentLinkedQueue<>(); - - ZoneContainer(ManagedZone zone) { - this.zone = zone; - this.dnsRecords.set(ImmutableSortedMap.of()); - } - - ManagedZone zone() { - return zone; - } - - AtomicReference> dnsRecords() { - return dnsRecords; - } - - ConcurrentLinkedQueue changes() { - return changes; - } - - Change findChange(String changeId) { - for (Change current : changes) { - if (changeId.equals(current.getId())) { - return current; - } - } - return null; - } - } - - static class Response { - private final int code; - private final String body; - - Response(int code, String body) { - this.code = code; - this.body = body; - } - - int code() { - return code; - } - - String body() { - return body; - } - } - - private enum Error { - REQUIRED(400, "global", "required", "REQUIRED"), - INTERNAL_ERROR(500, "global", "internalError", "INTERNAL_ERROR"), - BAD_REQUEST(400, "global", "badRequest", "BAD_REQUEST"), - INVALID(400, "global", "invalid", "INVALID"), - CONTAINER_NOT_EMPTY(400, "global", "containerNotEmpty", "CONTAINER_NOT_EMPTY"), - NOT_AVAILABLE(400, "global", "managedZoneDnsNameNotAvailable", "NOT_AVAILABLE"), - NOT_FOUND(404, "global", "notFound", "NOT_FOUND"), - ALREADY_EXISTS(409, "global", "alreadyExists", "ALREADY_EXISTS"), - CONDITION_NOT_MET(412, "global", "conditionNotMet", "CONDITION_NOT_MET"), - INVALID_ZONE_APEX(400, "global", "invalidZoneApex", "INVALID_ZONE_APEX"); - - private final int code; - private final String domain; - private final String reason; - private final String status; - - Error(int code, String domain, String reason, String status) { - this.code = code; - this.domain = domain; - this.reason = reason; - this.status = status; - } - - Response response(String message) { - try { - return new Response(code, toJson(message)); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response("Error when generating JSON error response."); - } - } - - private String toJson(String message) throws IOException { - Map errors = new HashMap<>(); - errors.put("domain", domain); - errors.put("message", message); - errors.put("reason", reason); - Map args = new HashMap<>(); - args.put("errors", ImmutableList.of(errors)); - args.put("code", code); - args.put("message", message); - args.put("status", status); - return jsonFactory.toString(ImmutableMap.of("error", args)); - } - } - - private class RequestHandler implements HttpHandler { - - private Response pickHandler(HttpExchange exchange, CallRegex regex) { - URI relative = BASE_CONTEXT.relativize(exchange.getRequestURI()); - 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(); - switch (regex) { - case CHANGE_GET: - return getChange(projectId, zoneName, changeId, query); - case CHANGE_LIST: - return listChanges(projectId, zoneName, query); - case ZONE_GET: - return getZone(projectId, zoneName, query); - case ZONE_DELETE: - return deleteZone(projectId, zoneName); - case ZONE_LIST: - return listZones(projectId, query); - case PROJECT_GET: - return getProject(projectId, query); - case RECORD_LIST: - return listDnsRecords(projectId, zoneName, query); - case ZONE_CREATE: - try { - return handleZoneCreate(exchange, projectId, query); - } catch (IOException ex) { - return Error.BAD_REQUEST.response(ex.getMessage()); - } - case CHANGE_CREATE: - try { - return handleChangeCreate(exchange, projectId, zoneName, query); - } catch (IOException ex) { - return Error.BAD_REQUEST.response(ex.getMessage()); - } - case BATCH: - try { - return handleBatch(exchange); - } catch (IOException | URISyntaxException ex) { - return Error.BAD_REQUEST.response(ex.getMessage()); - } - default: - return Error.INTERNAL_ERROR.response("Operation without a handler."); - } - } - - @Override - public void handle(HttpExchange exchange) throws IOException { - String requestMethod = exchange.getRequestMethod(); - String rawPath = exchange.getRequestURI().getRawPath(); - for (CallRegex regex : CallRegex.values()) { - if (requestMethod.equals(regex.method) && rawPath.matches(regex.pathRegex)) { - Response response = pickHandler(exchange, regex); - if (response != null) { - /* null response is returned by batch request, because it handles writing - the response on its own */ - writeResponse(exchange, response); - } - return; - } - } - writeResponse(exchange, Error.NOT_FOUND.response(String.format( - "The url %s for %s method does not match any API call.", - requestMethod, exchange.getRequestURI()))); - } - - private Response handleBatch(final HttpExchange exchange) throws IOException, - URISyntaxException { - String contentType = exchange.getRequestHeaders().getFirst("Content-type"); - if (contentType != null) { - 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]; - boolean nextPart = multipartStream.skipPreamble(); - while (nextPart) { - String line; - String contentId = null; - String headers = multipartStream.readHeaders(); - Scanner scanner = new Scanner(headers); - while (scanner.hasNextLine()) { - line = scanner.nextLine(); - if (line.toLowerCase().startsWith("content-id")) { - contentId = line.split(":")[1].trim(); - } - } - // TODO: remove and write directly to socket once api client provides a complete - // location line (e.g. GET /aaa/bbb HTTP/1.0) - // and uses a request path for location instead of a complete URL. - ByteArrayOutputStream bouts = new ByteArrayOutputStream(); - multipartStream.readBodyData(bouts); - byte[] contentBytes = bouts.toByteArray(); - int indexOfCr = -1; - for (int i = 0; i < contentBytes.length; i++) { - if (contentBytes[i] == '\r') { - indexOfCr = i; - break; - } - } - Socket socket = new Socket("127.0.0.1", server.getAddress().getPort()); - OutputStream socketOutput = socket.getOutputStream(); - InputStream socketInput = socket.getInputStream(); - //multipartStream.readBodyData(socketOutput); - if (indexOfCr < 0) { - socketOutput.write(contentBytes); - } else { - String[] requestLine = - new String(contentBytes, 0, indexOfCr, StandardCharsets.UTF_8).split(" "); - socketOutput.write(requestLine[0].getBytes()); - socketOutput.write(' '); - URI uri = new URI(requestLine[1]); - socketOutput.write(uri.getRawPath().getBytes()); - if (uri.getRawQuery() != null) { - socketOutput.write('?'); - socketOutput.write(uri.getRawQuery().getBytes()); - } - if (uri.getRawFragment() != null) { - socketOutput.write('#'); - socketOutput.write(uri.getRawFragment().getBytes()); - } - socketOutput.write(" HTTP/1.0".getBytes()); - socketOutput.write(contentBytes, indexOfCr, contentBytes.length - indexOfCr); - } - socketOutput.flush(); - out.write(RESPONSE_SEPARATOR.getBytes()); - out.write("Content-Type: application/http\r\n".getBytes()); - out.write(("Content-ID: " + contentId + "\r\n\r\n").getBytes()); - int length; - while ((length = socketInput.read(bytes)) != -1) { - out.write(bytes, 0, length); - } - socket.close(); - nextPart = multipartStream.skipPreamble(); - } - 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. - */ - private Response handleChangeCreate(HttpExchange exchange, String projectId, String zoneName, - String query) throws IOException { - String requestBody = decodeContent(exchange.getRequestHeaders(), exchange.getRequestBody()); - Change change; - try { - change = jsonFactory.fromString(requestBody, Change.class); - } catch (IllegalArgumentException ex) { - return Error.REQUIRED.response( - "The 'entity.change' parameter is required but was missing."); - } - String[] fields = OptionParsers.parseGetOptions(query); - return createChange(projectId, zoneName, change, fields); - } - - /** - * @throws IOException if the request cannot be parsed. - */ - private Response handleZoneCreate(HttpExchange exchange, String projectId, String query) - throws IOException { - String requestBody = decodeContent(exchange.getRequestHeaders(), exchange.getRequestBody()); - ManagedZone zone; - try { - zone = jsonFactory.fromString(requestBody, ManagedZone.class); - } catch (IllegalArgumentException ex) { - return Error.REQUIRED.response( - "The 'entity.managedZone' parameter is required but was missing."); - } - String[] options = OptionParsers.parseGetOptions(query); - return createZone(projectId, zone, options); - } - } - - private LocalDnsHelper(long delay) { - this.delayChange = delay; - try { - server = HttpServer.create(new InetSocketAddress(0), 0); - port = server.getAddress().getPort(); - server.setExecutor(Executors.newCachedThreadPool()); - server.createContext("/", new RequestHandler()); - } catch (IOException e) { - throw new RuntimeException("Could not bind the mock DNS server.", e); - } - } - - /** - * Accessor for testing purposes. - */ - ConcurrentSkipListMap projects() { - return projects; - } - - /** - * Creates new {@code LocalDnsHelper} instance that listens to requests on the local machine. This - * instance processes changes in separate thread. The parameter determines how long a thread - * should wait before processing a change. If it is set to 0, the threading is turned off and the - * mock will behave synchronously. - * - * @param delay delay for processing changes in ms or 0 for synchronous processing - */ - public static LocalDnsHelper create(Long delay) { - return new LocalDnsHelper(delay); - } - - /** - * Returns a {@link DnsOptions} instance that sets the host to use the mock server. - */ - @Deprecated - public DnsOptions options() { - return getOptions(); - } - - /** - * Returns a {@link DnsOptions} instance that sets the host to use the mock server. - */ - public DnsOptions getOptions() { - return DnsOptions.newBuilder() - .setProjectId(PROJECT_ID) - .setHost("http://localhost:" + port) - .setCredentials(NoCredentials.getInstance()) - .build(); - } - - /** - * Starts the thread that runs the local DNS server. - */ - public void start() { - server.start(); - } - - /** - * Stops the thread that runs the mock DNS server. - */ - public void stop() { - server.stop(1); - } - - private static void writeResponse(HttpExchange exchange, Response response) { - exchange.getResponseHeaders().set("Content-type", "application/json; charset=UTF-8"); - OutputStream outputStream = exchange.getResponseBody(); - try { - exchange.getResponseHeaders().add("Connection", "close"); - exchange.sendResponseHeaders(response.code(), response.body().length()); - if (response.code() != 204) { - // the server automatically sends headers and closes output stream when 204 is returned - outputStream.write(response.body().getBytes(StandardCharsets.UTF_8)); - } - outputStream.close(); - } catch (IOException e) { - log.log(Level.WARNING, "IOException encountered when sending response.", e); - } - } - - 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; - try { - if (contentEncoding != null && !contentEncoding.isEmpty()) { - String encoding = contentEncoding.get(0); - if (ENCODINGS.contains(encoding)) { - input = new GZIPInputStream(inputStream); - } else if (!"identity".equals(encoding)) { - throw new IOException( - "The request has the following unsupported HTTP content encoding: " + encoding); - } - } - return new String(ByteStreams.toByteArray(input), StandardCharsets.UTF_8); - } catch (IOException e) { - throw new IOException("Exception encountered when decoding request content.", e); - } - } - - /** - * Generates a JSON response. - * - * @param context managedZones | projects | rrsets | changes - */ - @VisibleForTesting - static Response toListResponse(List serializedObjects, String context, String pageToken, - boolean includePageToken) { - StringBuilder responseBody = new StringBuilder(); - responseBody.append("{\"").append(context).append("\": ["); - Joiner.on(",").appendTo(responseBody, serializedObjects); - responseBody.append(']'); - // add page token only if it exists and is asked for - if (pageToken != null && includePageToken) { - responseBody.append(",\"nextPageToken\": \"").append(pageToken).append('"'); - } - responseBody.append('}'); - return new Response(HTTP_OK, responseBody.toString()); - } - - /** - * Prepares record sets that are created by default for each zone. - */ - private static ImmutableSortedMap defaultRecords(ManagedZone zone) { - ResourceRecordSet soa = new ResourceRecordSet(); - soa.setTtl(21600); - soa.setName(zone.getDnsName()); - soa.setRrdatas(ImmutableList.of( - // taken from the service - "ns-cloud-c1.googledomains.com. cloud-dns-hostmaster.google.com. 0 21600 3600 1209600 312" - )); - soa.setType("SOA"); - ResourceRecordSet ns = new ResourceRecordSet(); - ns.setTtl(21600); - ns.setName(zone.getDnsName()); - ns.setRrdatas(zone.getNameServers()); - ns.setType("NS"); - String nsId = getUniqueId(ImmutableSet.of()); - String soaId = getUniqueId(ImmutableSet.of(nsId)); - return ImmutableSortedMap.of(nsId, ns, soaId, soa); - } - - /** - * Returns a list of four nameservers randomly chosen from the predefined set. - */ - @VisibleForTesting - static List randomNameservers() { - ArrayList nameservers = Lists.newArrayList( - "dns1.googlecloud.com", "dns2.googlecloud.com", "dns3.googlecloud.com", - "dns4.googlecloud.com", "dns5.googlecloud.com", "dns6.googlecloud.com" - ); - while (nameservers.size() != 4) { - int index = ID_GENERATOR.nextInt(nameservers.size()); - nameservers.remove(index); - } - return nameservers; - } - - /** - * Returns a hex string id (used for a record set) unique within the set of ids. - */ - @VisibleForTesting - static String getUniqueId(Set ids) { - String id; - do { - id = Long.toHexString(System.currentTimeMillis()) - + Long.toHexString(Math.abs(ID_GENERATOR.nextLong())); - } while (ids.contains(id)); - return id; - } - - /** - * Tests if a record set matches name and type (if provided). Used for filtering. - */ - @VisibleForTesting - static boolean matchesCriteria(ResourceRecordSet recordSet, String name, String type) { - if (type != null && !recordSet.getType().equals(type)) { - return false; - } - return name == null || recordSet.getName().equals(name); - } - - /** - * Returns a project container. Never returns {@code null} because we assume that all projects - * exists. - */ - private ProjectContainer findProject(String projectId) { - ProjectContainer defaultProject = createProject(projectId); - projects.putIfAbsent(projectId, defaultProject); - return projects.get(projectId); - } - - /** - * Returns a zone container. Returns {@code null} if zone does not exist within project. - */ - @VisibleForTesting - ZoneContainer findZone(String projectId, String zoneName) { - ProjectContainer projectContainer = findProject(projectId); // never null - return projectContainer.zones().get(zoneName); - } - - /** - * Returns a change found by its id. Returns {@code null} if such a change does not exist. - */ - @VisibleForTesting - Change findChange(String projectId, String zoneName, String changeId) { - ZoneContainer wrapper = findZone(projectId, zoneName); - return wrapper == null ? null : wrapper.findChange(changeId); - } - - /** - * Returns a response to getChange service call. - */ - @VisibleForTesting - Response getChange(String projectId, String zoneName, String changeId, String query) { - Change change = findChange(projectId, zoneName, changeId); - if (change == null) { - ZoneContainer zone = findZone(projectId, zoneName); - if (zone == null) { - return Error.NOT_FOUND.response(String.format( - "The 'parameters.managedZone' resource named '%s' does not exist.", zoneName)); - } - return Error.NOT_FOUND.response(String.format( - "The 'parameters.changeId' resource named '%s' does not exist.", changeId)); - } - String[] fields = OptionParsers.parseGetOptions(query); - Change result = OptionParsers.extractFields(change, fields); - try { - return new Response(HTTP_OK, jsonFactory.toString(result)); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response(String.format( - "Error when serializing change %s in managed zone %s in project %s.", - changeId, zoneName, projectId)); - } - } - - /** - * Returns a response to getZone service call. - */ - @VisibleForTesting - Response getZone(String projectId, String zoneName, String query) { - ZoneContainer container = findZone(projectId, zoneName); - if (container == null) { - return Error.NOT_FOUND.response(String.format( - "The 'parameters.managedZone' resource named '%s' does not exist.", zoneName)); - } - String[] fields = OptionParsers.parseGetOptions(query); - ManagedZone result = OptionParsers.extractFields(container.zone(), fields); - try { - return new Response(HTTP_OK, jsonFactory.toString(result)); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response(String.format( - "Error when serializing managed zone %s in project %s.", zoneName, projectId)); - } - } - - /** - * We assume that every project exists. If we do not have it in the collection yet, we just create - * a new default project instance with default quota. - */ - @VisibleForTesting - Response getProject(String projectId, String query) { - String[] fields = OptionParsers.parseGetOptions(query); - Project project = findProject(projectId).project(); // creates project if needed - Project result = OptionParsers.extractFields(project, fields); - try { - return new Response(HTTP_OK, jsonFactory.toString(result)); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response( - String.format("Error when serializing project %s.", projectId)); - } - } - - /** - * Creates a project. It generates a project number randomly. - */ - private ProjectContainer createProject(String projectId) { - Quota quota = new Quota(); - quota.setManagedZones(10000); - quota.setRrsetsPerManagedZone(10000); - quota.setRrsetAdditionsPerChange(100); - quota.setRrsetDeletionsPerChange(100); - quota.setTotalRrdataSizePerChange(10000); - quota.setResourceRecordsPerRrset(100); - Project project = new Project(); - project.setId(projectId); - project.setNumber(new BigInteger(String.valueOf( - Math.abs(ID_GENERATOR.nextLong() % Long.MAX_VALUE)))); - project.setQuota(quota); - return new ProjectContainer(project); - } - - @VisibleForTesting - Response deleteZone(String projectId, String zoneName) { - ZoneContainer zone = findZone(projectId, zoneName); - ImmutableSortedMap rrsets = zone == null - ? ImmutableSortedMap.of() : zone.dnsRecords().get(); - ImmutableList defaults = ImmutableList.of("NS", "SOA"); - for (ResourceRecordSet current : rrsets.values()) { - if (!defaults.contains(current.getType())) { - return Error.CONTAINER_NOT_EMPTY.response(String.format( - "The resource named '%s' cannot be deleted because it is not empty", zoneName)); - } - } - ProjectContainer projectContainer = projects.get(projectId); - ZoneContainer previous = projectContainer.zones.remove(zoneName); - return previous == null - ? Error.NOT_FOUND.response(String.format( - "The 'parameters.managedZone' resource named '%s' does not exist.", zoneName)) - : new Response(HTTP_NO_CONTENT, "{}"); - } - - /** - * Creates new managed zone and stores it in the collection. Assumes that project exists. - */ - @VisibleForTesting - Response createZone(String projectId, ManagedZone zone, String... fields) { - Response errorResponse = checkZone(zone); - if (errorResponse != null) { - return errorResponse; - } - ManagedZone completeZone = new ManagedZone(); - completeZone.setName(zone.getName()); - completeZone.setDnsName(zone.getDnsName()); - completeZone.setDescription(zone.getDescription()); - completeZone.setNameServerSet(zone.getNameServerSet()); - completeZone.setCreationTime(ISODateTimeFormat.dateTime().withZoneUTC() - .print(System.currentTimeMillis())); - completeZone.setId(BigInteger.valueOf(Math.abs(ID_GENERATOR.nextLong() % Long.MAX_VALUE))); - completeZone.setNameServers(randomNameservers()); - ZoneContainer zoneContainer = new ZoneContainer(completeZone); - ImmutableSortedMap defaultsRecords = defaultRecords(completeZone); - zoneContainer.dnsRecords().set(defaultsRecords); - Change change = new Change(); - change.setAdditions(ImmutableList.copyOf(defaultsRecords.values())); - change.setStatus("done"); - change.setId("0"); - change.setStartTime(ISODateTimeFormat.dateTime().withZoneUTC() - .print(System.currentTimeMillis())); - zoneContainer.changes().add(change); - ProjectContainer projectContainer = findProject(projectId); - ZoneContainer oldValue = projectContainer.zones().putIfAbsent( - completeZone.getName(), zoneContainer); - if (oldValue != null) { - return Error.ALREADY_EXISTS.response(String.format( - "The resource 'entity.managedZone' named '%s' already exists", completeZone.getName())); - } - ManagedZone result = OptionParsers.extractFields(completeZone, fields); - try { - return new Response(HTTP_OK, jsonFactory.toString(result)); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response( - String.format("Error when serializing managed zone %s.", result.getName())); - } - } - - /** - * Creates a new change, stores it, and if delayChange > 0, invokes processing in a new thread. - */ - Response createChange(String projectId, String zoneName, Change change, String... fields) { - ZoneContainer zoneContainer = findZone(projectId, zoneName); - if (zoneContainer == null) { - return Error.NOT_FOUND.response(String.format( - "The 'parameters.managedZone' resource named %s does not exist.", zoneName)); - } - Response response = checkChange(change, zoneContainer); - if (response != null) { - return response; - } - Change completeChange = new Change(); - if (change.getAdditions() != null) { - completeChange.setAdditions(ImmutableList.copyOf(change.getAdditions())); - } - if (change.getDeletions() != null) { - completeChange.setDeletions(ImmutableList.copyOf(change.getDeletions())); - } - /* We need to set ID for the change. We are working in concurrent environment. We know that the - element fell on an index between 1 and maxId (index 0 is the default change which creates SOA - and NS), so we will reset all IDs between 0 and maxId (all of them are valid for the respective - objects). */ - ConcurrentLinkedQueue changeSequence = zoneContainer.changes(); - changeSequence.add(completeChange); - int maxId = changeSequence.size(); - int index = 0; - for (Change c : changeSequence) { - if (index == maxId) { - break; - } - c.setId(String.valueOf(index++)); - } - completeChange.setStatus("pending"); - completeChange.setStartTime(ISODateTimeFormat.dateTime().withZoneUTC() - .print(System.currentTimeMillis())); - invokeChange(projectId, zoneName, completeChange.getId()); - Change result = OptionParsers.extractFields(completeChange, fields); - try { - return new Response(HTTP_OK, jsonFactory.toString(result)); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response( - String.format("Error when serializing change %s in managed zone %s in project %s.", - result.getId(), zoneName, projectId)); - } - } - - /** - * Applies change. Uses a different pooled thread which applies the change only if {@code - * delayChange} is > 0. - */ - private void invokeChange(final String projectId, final String zoneName, - final String changeId) { - if (delayChange > 0) { - EXECUTORS.schedule(new Runnable() { - @Override - public void run() { - applyExistingChange(projectId, zoneName, changeId); - } - }, delayChange, TimeUnit.MILLISECONDS); - } else { - applyExistingChange(projectId, zoneName, changeId); - } - } - - /** - * Applies changes to a zone. Repeatedly tries until succeeds. Thread safe and deadlock safe. - */ - private void applyExistingChange(String projectId, String zoneName, String changeId) { - Change change = findChange(projectId, zoneName, changeId); - if (change == null) { - return; // no such change exists, nothing to do - } - ZoneContainer wrapper = findZone(projectId, zoneName); - if (wrapper == null) { - return; // no such zone exists; it might have been deleted by another thread - } - AtomicReference> dnsRecords = - wrapper.dnsRecords(); - while (true) { - // managed zone must have a set of records which is not null - ImmutableSortedMap original = dnsRecords.get(); - // the copy will be populated when handling deletions - SortedMap copy = new TreeMap<>(); - // apply deletions first - List deletions = change.getDeletions(); - if (deletions != null) { - for (Map.Entry entry : original.entrySet()) { - if (!deletions.contains(entry.getValue())) { - copy.put(entry.getKey(), entry.getValue()); - } - } - } else { - copy.putAll(original); - } - // apply additions - List additions = change.getAdditions(); - if (additions != null) { - for (ResourceRecordSet addition : additions) { - ResourceRecordSet rrset = new ResourceRecordSet(); - rrset.setName(addition.getName()); - rrset.setRrdatas(ImmutableList.copyOf(addition.getRrdatas())); - rrset.setTtl(addition.getTtl()); - rrset.setType(addition.getType()); - String id = getUniqueId(copy.keySet()); - copy.put(id, rrset); - } - } - boolean success = dnsRecords.compareAndSet(original, ImmutableSortedMap.copyOf(copy)); - if (success) { - break; // success if no other thread modified the value in the meantime - } - } - change.setStatus("done"); - } - - /** - * Lists zones. Next page token is the last listed zone name and is returned only of there is more - * to list and if the user does not exclude nextPageToken from field options. - */ - @VisibleForTesting - Response listZones(String projectId, String query) { - Map options = OptionParsers.parseListZonesOptions(query); - Response response = checkListOptions(options); - if (response != null) { - return response; - } - ConcurrentSkipListMap containers = findProject(projectId).zones(); - String[] fields = (String[]) options.get("fields"); - String dnsName = (String) options.get("dnsName"); - String pageToken = (String) options.get("pageToken"); - Integer maxResults = options.get("maxResults") == null - ? null : Integer.valueOf((String) options.get("maxResults")); - boolean sizeReached = false; - boolean hasMorePages = false; - LinkedList serializedZones = new LinkedList<>(); - String lastZoneName = null; - ConcurrentNavigableMap fragment = - pageToken != null ? containers.tailMap(pageToken, false) : containers; - for (ZoneContainer zoneContainer : fragment.values()) { - ManagedZone zone = zoneContainer.zone(); - if (dnsName == null || zone.getDnsName().equals(dnsName)) { - if (sizeReached) { - // we do not add this, just note that there would be more and there should be a token - hasMorePages = true; - break; - } else { - try { - lastZoneName = zone.getName(); - serializedZones.addLast(jsonFactory.toString( - OptionParsers.extractFields(zone, fields))); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response(String.format( - "Error when serializing managed zone %s in project %s", lastZoneName, projectId)); - } - } - } - sizeReached = maxResults != null && maxResults.equals(serializedZones.size()); - } - boolean includePageToken = - hasMorePages && (fields == null || Arrays.asList(fields).contains("nextPageToken")); - return toListResponse(serializedZones, "managedZones", lastZoneName, includePageToken); - } - - /** - * Lists record sets for a zone. Next page token is the ID of the last record listed. - */ - @VisibleForTesting - Response listDnsRecords(String projectId, String zoneName, String query) { - Map options = OptionParsers.parseListDnsRecordsOptions(query); - Response response = checkListOptions(options); - if (response != null) { - return response; - } - ZoneContainer zoneContainer = findZone(projectId, zoneName); - if (zoneContainer == null) { - return Error.NOT_FOUND.response(String.format( - "The 'parameters.managedZone' resource named '%s' does not exist.", zoneName)); - } - ImmutableSortedMap dnsRecords = zoneContainer.dnsRecords().get(); - String[] fields = (String[]) options.get("fields"); - String name = (String) options.get("name"); - String type = (String) options.get("type"); - String pageToken = (String) options.get("pageToken"); - ImmutableSortedMap fragment = - pageToken != null ? dnsRecords.tailMap(pageToken, false) : dnsRecords; - Integer maxResults = options.get("maxResults") == null - ? null : Integer.valueOf((String) options.get("maxResults")); - boolean sizeReached = false; - boolean hasMorePages = false; - LinkedList serializedRrsets = new LinkedList<>(); - String lastRecordId = null; - for (String recordSetId : fragment.keySet()) { - ResourceRecordSet recordSet = fragment.get(recordSetId); - if (matchesCriteria(recordSet, name, type)) { - if (sizeReached) { - // we do not add this, just note that there would be more and there should be a token - hasMorePages = true; - break; - } else { - lastRecordId = recordSetId; - try { - serializedRrsets.addLast(jsonFactory.toString( - OptionParsers.extractFields(recordSet, fields))); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response(String.format( - "Error when serializing resource record set in managed zone %s in project %s", - zoneName, projectId)); - } - } - } - sizeReached = maxResults != null && maxResults.equals(serializedRrsets.size()); - } - boolean includePageToken = - hasMorePages && (fields == null || Arrays.asList(fields).contains("nextPageToken")); - return toListResponse(serializedRrsets, "rrsets", lastRecordId, includePageToken); - } - - /** - * Lists changes. Next page token is the ID of the last change listed. - */ - @VisibleForTesting - Response listChanges(String projectId, String zoneName, String query) { - Map options = OptionParsers.parseListChangesOptions(query); - Response response = checkListOptions(options); - if (response != null) { - return response; - } - ZoneContainer zoneContainer = findZone(projectId, zoneName); - if (zoneContainer == null) { - return Error.NOT_FOUND.response(String.format( - "The 'parameters.managedZone' resource named '%s' does not exist", zoneName)); - } - // take a sorted snapshot of the current change list - NavigableMap changes = new TreeMap<>(); - for (Change c : zoneContainer.changes()) { - if (c.getId() != null) { - changes.put(Integer.valueOf(c.getId()), c); - } - } - String[] fields = (String[]) options.get("fields"); - String sortOrder = (String) options.get("sortOrder"); - String pageToken = (String) options.get("pageToken"); - Integer maxResults = options.get("maxResults") == null - ? null : Integer.valueOf((String) options.get("maxResults")); - // as the only supported field is change sequence, we are not reading sortBy - NavigableSet keys; - if ("descending".equals(sortOrder)) { - keys = changes.descendingKeySet(); - } else { - keys = changes.navigableKeySet(); - } - Integer from = null; - try { - from = Integer.valueOf(pageToken); - } catch (NumberFormatException ex) { - // ignore page token - } - keys = from != null ? keys.tailSet(from, false) : keys; - NavigableMap fragment = - from != null && changes.containsKey(from) ? changes.tailMap(from, false) : changes; - boolean sizeReached = false; - boolean hasMorePages = false; - LinkedList serializedResults = new LinkedList<>(); - String lastChangeId = null; - for (Integer key : keys) { - Change change = fragment.get(key); - if (sizeReached) { - // we do not add this, just note that there would be more and there should be a token - hasMorePages = true; - break; - } else { - lastChangeId = change.getId(); - try { - serializedResults.addLast(jsonFactory.toString( - OptionParsers.extractFields(change, fields))); - } catch (IOException e) { - return Error.INTERNAL_ERROR.response(String.format( - "Error when serializing change %s in managed zone %s in project %s", - lastChangeId, zoneName, projectId)); - } - } - sizeReached = maxResults != null && maxResults.equals(serializedResults.size()); - } - boolean includePageToken = - hasMorePages && (fields == null || Arrays.asList(fields).contains("nextPageToken")); - return toListResponse(serializedResults, "changes", lastChangeId, includePageToken); - } - - /** - * Validates a zone to be created. - */ - private static Response checkZone(ManagedZone zone) { - if (zone.getName() == null) { - return Error.REQUIRED.response( - "The 'entity.managedZone.name' parameter is required but was missing."); - } - if (zone.getDnsName() == null) { - return Error.REQUIRED.response( - "The 'entity.managedZone.dnsName' parameter is required but was missing."); - } - if (zone.getDescription() == null) { - return Error.REQUIRED.response( - "The 'entity.managedZone.description' parameter is required but was missing."); - } - try { - int number = Integer.valueOf(zone.getName()); - return Error.INVALID.response( - String.format("Invalid value for 'entity.managedZone.name': '%s'", number)); - } catch (NumberFormatException ex) { - // expected - } - if (zone.getName().isEmpty() || zone.getName().length() > 32 - || !ZONE_NAME_RE.matcher(zone.getName()).matches()) { - return Error.INVALID.response( - String.format("Invalid value for 'entity.managedZone.name': '%s'", zone.getName())); - } - if (zone.getDnsName().isEmpty() || !zone.getDnsName().endsWith(".")) { - return Error.INVALID.response( - String.format("Invalid value for 'entity.managedZone.dnsName': '%s'", zone.getDnsName())); - } - if (FORBIDDEN.contains(zone.getDnsName())) { - return Error.NOT_AVAILABLE.response(String.format( - "The '%s' managed zone is not available to be created.", zone.getDnsName())); - } - return null; - } - - /** - * Validates a change to be created. - */ - @VisibleForTesting - static Response checkChange(Change change, ZoneContainer zone) { - if ((change.getDeletions() == null || change.getDeletions().size() <= 0) - && (change.getAdditions() == null || change.getAdditions().size() <= 0)) { - return Error.REQUIRED.response("The 'entity.change' parameter is required but was missing."); - } - if (change.getAdditions() != null) { - int counter = 0; - for (ResourceRecordSet addition : change.getAdditions()) { - Response response = checkRrset(addition, zone, counter, "additions"); - if (response != null) { - return response; - } - counter++; - } - } - if (change.getDeletions() != null) { - int counter = 0; - for (ResourceRecordSet deletion : change.getDeletions()) { - Response response = checkRrset(deletion, zone, counter, "deletions"); - if (response != null) { - return response; - } - counter++; - } - } - return checkAdditionsDeletions(change.getAdditions(), change.getDeletions(), zone); - // null if everything is ok - } - - /** - * Checks a rrset within a change. - * - * @param type [additions|deletions] - * @param index the index or addition or deletion in the list - * @param zone the zone that this change is applied to - */ - @VisibleForTesting - static Response checkRrset(ResourceRecordSet rrset, ZoneContainer zone, int index, String type) { - if (rrset.getName() == null || !rrset.getName().endsWith(zone.zone().getDnsName())) { - return Error.INVALID.response(String.format( - "Invalid value for 'entity.change.%s[%s].name': '%s'", type, index, rrset.getName())); - } - if (rrset.getType() == null || !TYPES.contains(rrset.getType())) { - return Error.INVALID.response(String.format( - "Invalid value for 'entity.change.%s[%s].type': '%s'", type, index, rrset.getType())); - } - if (rrset.getTtl() != null && rrset.getTtl() != 0 && rrset.getTtl() < 0) { - return Error.INVALID.response(String.format( - "Invalid value for 'entity.change.%s[%s].ttl': '%s'", type, index, rrset.getTtl())); - } - if (rrset.getRrdatas() == null || rrset.isEmpty()) { - return Error.INVALID.response(String.format( - "Invalid value for 'entity.change.%s[%s].rrdata': '%s'", type, index, "")); - } - int counter = 0; - for (String record : rrset.getRrdatas()) { - if (!checkRrData(record, rrset.getType())) { - return Error.INVALID.response(String.format( - "Invalid value for 'entity.change.%s[%s].rrdata[%s]': '%s'", - type, index, counter, record)); - } - counter++; - } - if ("deletions".equals(type)) { - // check that deletion has a match by name and type - boolean found = false; - for (ResourceRecordSet wrappedRrset : zone.dnsRecords().get().values()) { - if (rrset.getName().equals(wrappedRrset.getName()) - && rrset.getType().equals(wrappedRrset.getType())) { - found = true; - break; - } - } - if (!found) { - return Error.NOT_FOUND.response(String.format( - "The 'entity.change.deletions[%s]' resource named '%s (%s)' does not exist.", - index, rrset.getName(), rrset.getType())); - } - // if found, we still need an exact match - if ("deletions".equals(type) - && !zone.dnsRecords().get().containsValue(rrset)) { - // such a record does not exist - return Error.CONDITION_NOT_MET.response(String.format( - "Precondition not met for 'entity.change.deletions[%s]", index)); - } - } - return null; - } - - /** - * Checks against duplicate additions (for each record set to be added that already exists, we - * must have a matching deletion. Furthermore, check that mandatory SOA and NS records stay. - */ - static Response checkAdditionsDeletions(List additions, - List deletions, ZoneContainer zone) { - if (additions != null) { - int index = 0; - for (ResourceRecordSet rrset : additions) { - for (ResourceRecordSet wrappedRrset : zone.dnsRecords().get().values()) { - if (rrset.getName().equals(wrappedRrset.getName()) - && rrset.getType().equals(wrappedRrset.getType()) - // such a record set exists and we must have a deletion - && (deletions == null || !deletions.contains(wrappedRrset))) { - return Error.ALREADY_EXISTS.response(String.format( - "The 'entity.change.additions[%s]' resource named '%s (%s)' already exists.", - index, rrset.getName(), rrset.getType())); - } - } - if (rrset.getType().equals("SOA") && findByNameAndType(deletions, null, "SOA") == null) { - return Error.INVALID_ZONE_APEX.response(String.format("The resource record set 'entity" - + ".change.additions[%s]' is invalid because a zone must contain exactly one resource" - + " record set of type 'SOA' at the apex.", index)); - } - if (rrset.getType().equals("NS") && findByNameAndType(deletions, null, "NS") == null) { - return Error.INVALID_ZONE_APEX.response(String.format("The resource record set 'entity" - + ".change.additions[%s]' is invalid because a zone must contain exactly one resource" - + " record set of type 'NS' at the apex.", index)); - } - index++; - } - } - if (deletions != null) { - int index = 0; - for (ResourceRecordSet rrset : deletions) { - if (rrset.getType().equals("SOA") && findByNameAndType(additions, null, "SOA") == null) { - return Error.INVALID_ZONE_APEX.response(String.format("The resource record set 'entity" - + ".change.deletions[%s]' is invalid because a zone must contain exactly one resource" - + " record set of type 'SOA' at the apex.", index)); - } - if (rrset.getType().equals("NS") && findByNameAndType(additions, null, "NS") == null) { - return Error.INVALID_ZONE_APEX.response(String.format("The resource record set 'entity" - + ".change.deletions[%s]' is invalid because a zone must contain exactly one resource" - + " record set of type 'NS' at the apex.", index)); - } - index++; - } - } - return null; - } - - /** - * Helper for searching rrsets in a collection. - */ - private static ResourceRecordSet findByNameAndType(Iterable recordSets, - String name, String type) { - if (recordSets != null) { - for (ResourceRecordSet rrset : recordSets) { - if ((name == null || name.equals(rrset.getName())) - && (type == null || type.equals(rrset.getType()))) { - return rrset; - } - } - } - return null; - } - - /** - * We only provide the most basic validation for A and AAAA record sets. - */ - static boolean checkRrData(String data, String type) { - switch (type) { - case "A": - return !data.contains(":") && isInetAddress(data); - case "AAAA": - return data.contains(":") && isInetAddress(data); - default: - return true; - } - } - - /** - * Check supplied listing options. - */ - @VisibleForTesting - static Response checkListOptions(Map options) { - // for general listing - String maxResultsString = (String) options.get("maxResults"); - if (maxResultsString != null) { - Integer maxResults; - try { - maxResults = Integer.valueOf(maxResultsString); - } catch (NumberFormatException ex) { - return Error.INVALID.response(String.format( - "Invalid integer value': '%s'.", maxResultsString)); - } - if (maxResults <= 0) { - return Error.INVALID.response(String.format( - "Invalid value for 'parameters.maxResults': '%s'", maxResults)); - } - } - String dnsName = (String) options.get("dnsName"); - if (dnsName != null && !dnsName.endsWith(".")) { - return Error.INVALID.response(String.format( - "Invalid value for 'parameters.dnsName': '%s'", dnsName)); - } - // for listing record sets, name must be fully qualified - String name = (String) options.get("name"); - if (name != null && !name.endsWith(".")) { - return Error.INVALID.response(String.format( - "Invalid value for 'parameters.name': '%s'", name)); - } - String type = (String) options.get("type"); // must be provided with name - if (type != null) { - if (name == null) { - return Error.INVALID.response("Invalid value for 'parameters.name': '' " - + "(name must be specified if type is specified)"); - } - if (!TYPES.contains(type)) { - return Error.INVALID.response(String.format( - "Invalid value for 'parameters.type': '%s'", type)); - } - } - // for listing changes - String order = (String) options.get("sortOrder"); - if (order != null && !"ascending".equals(order) && !"descending".equals(order)) { - return Error.INVALID.response(String.format( - "Invalid value for 'parameters.sortOrder': '%s'", order)); - } - String sortBy = (String) options.get("sortBy"); // case insensitive - if (sortBy != null && !"changesequence".equals(sortBy.toLowerCase())) { - return Error.INVALID.response(String.format( - "Invalid string value: '%s'. Allowed values: [changesequence]", sortBy)); - } - return null; - } -} diff --git a/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/OptionParsers.java b/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/OptionParsers.java deleted file mode 100644 index 0543c6faab52..000000000000 --- a/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/OptionParsers.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.cloud.dns.testing; - -import com.google.api.services.dns.model.Change; -import com.google.api.services.dns.model.ManagedZone; -import com.google.api.services.dns.model.Project; -import com.google.api.services.dns.model.ResourceRecordSet; - -import java.util.HashMap; -import java.util.Map; - -/** - * Utility helpers for LocalDnsHelper. - */ -class OptionParsers { - - private OptionParsers() { - } - - static Map parseListZonesOptions(String query) { - Map options = new HashMap<>(); - if (query != null) { - String[] args = query.split("&"); - for (String arg : args) { - String[] argEntry = arg.split("="); - switch (argEntry[0]) { - case "fields": - // List fields are in the form "managedZones(field1, field2, ...),nextPageToken" - String replaced = argEntry[1].replace("managedZones(", ","); - replaced = replaced.replace(")", ","); - // we will get empty strings, but it does not matter, they will be ignored - options.put("fields", replaced.split(",")); - break; - case "dnsName": - options.put("dnsName", argEntry[1]); - break; - case "pageToken": - options.put("pageToken", argEntry[1]); - break; - case "maxResults": - // parsing to int is done while handling - options.put("maxResults", argEntry[1]); - break; - default: - break; - } - } - } - return options; - } - - static String[] parseGetOptions(String query) { - if (query != null) { - String[] args = query.split("&"); - for (String arg : args) { - String[] argEntry = arg.split("="); - if (argEntry[0].equals("fields")) { - // List fields are in the form "fields=field1, field2,..." - return argEntry[1].split(","); - } - } - } - return new String[0]; - } - - static ManagedZone extractFields(ManagedZone fullZone, String... fields) { - if (fields == null || fields.length == 0) { - return fullZone; - } - ManagedZone managedZone = new ManagedZone(); - for (String field : fields) { - switch (field) { - case "creationTime": - managedZone.setCreationTime(fullZone.getCreationTime()); - break; - case "description": - managedZone.setDescription(fullZone.getDescription()); - break; - case "dnsName": - managedZone.setDnsName(fullZone.getDnsName()); - break; - case "id": - managedZone.setId(fullZone.getId()); - break; - case "name": - managedZone.setName(fullZone.getName()); - break; - case "nameServerSet": - managedZone.setNameServerSet(fullZone.getNameServerSet()); - break; - case "nameServers": - managedZone.setNameServers(fullZone.getNameServers()); - break; - default: - break; - } - } - return managedZone; - } - - static Change extractFields(Change fullChange, String... fields) { - if (fields == null || fields.length == 0) { - return fullChange; - } - Change change = new Change(); - for (String field : fields) { - switch (field) { - case "additions": - change.setAdditions(fullChange.getAdditions()); - break; - case "deletions": - change.setDeletions(fullChange.getDeletions()); - break; - case "id": - change.setId(fullChange.getId()); - break; - case "startTime": - change.setStartTime(fullChange.getStartTime()); - break; - case "status": - change.setStatus(fullChange.getStatus()); - break; - default: - break; - } - } - return change; - } - - static Project extractFields(Project fullProject, String... fields) { - if (fields == null || fields.length == 0) { - return fullProject; - } - Project project = new Project(); - for (String field : fields) { - switch (field) { - case "id": - project.setId(fullProject.getId()); - break; - case "number": - project.setNumber(fullProject.getNumber()); - break; - case "quota": - project.setQuota(fullProject.getQuota()); - break; - default: - break; - } - } - return project; - } - - static ResourceRecordSet extractFields(ResourceRecordSet fullRecord, String... fields) { - if (fields == null || fields.length == 0) { - return fullRecord; - } - ResourceRecordSet recordSet = new ResourceRecordSet(); - for (String field : fields) { - switch (field) { - case "name": - recordSet.setName(fullRecord.getName()); - break; - case "rrdatas": - recordSet.setRrdatas(fullRecord.getRrdatas()); - break; - case "type": - recordSet.setType(fullRecord.getType()); - break; - case "ttl": - recordSet.setTtl(fullRecord.getTtl()); - break; - default: - break; - } - } - return recordSet; - } - - static Map parseListChangesOptions(String query) { - Map options = new HashMap<>(); - if (query != null) { - String[] args = query.split("&"); - for (String arg : args) { - String[] argEntry = arg.split("="); - switch (argEntry[0]) { - case "fields": - String replaced = argEntry[1].replace("changes(", ",").replace(")", ","); - options.put("fields", replaced.split(",")); // empty strings will be ignored - break; - case "pageToken": - options.put("pageToken", argEntry[1]); - break; - case "sortBy": - options.put("sortBy", argEntry[1]); - break; - case "sortOrder": - options.put("sortOrder", argEntry[1]); - break; - case "maxResults": - // parsing to int is done while handling - options.put("maxResults", argEntry[1]); - break; - default: - break; - } - } - } - return options; - } - - static Map parseListDnsRecordsOptions(String query) { - Map options = new HashMap<>(); - if (query != null) { - String[] args = query.split("&"); - for (String arg : args) { - String[] argEntry = arg.split("="); - switch (argEntry[0]) { - case "fields": - String replace = argEntry[1].replace("rrsets(", ","); - replace = replace.replace(")", ","); - options.put("fields", replace.split(",")); // empty strings do not matter - break; - case "name": - options.put("name", argEntry[1]); - break; - case "type": - options.put("type", argEntry[1]); - break; - case "pageToken": - options.put("pageToken", argEntry[1]); - break; - case "maxResults": - // parsing to int is done while handling - options.put("maxResults", argEntry[1]); - break; - default: - break; - } - } - } - return options; - } -} diff --git a/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/package-info.java b/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/package-info.java deleted file mode 100644 index 1f48ecf01607..000000000000 --- a/google-cloud-dns/src/main/java/com/google/cloud/dns/testing/package-info.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * A testing helper for Google Cloud DNS. - * - *

A simple usage example: - * Before the test: - *

 {@code
- * // Minimum delay before processing change requests (in ms). Setting the delay to 0 makes change
- * // request processing synchronous.
- * long delay = 0;
- * LocalDnsHelper dnsHelper = LocalDnsHelper.create(delay);
- * dnsHelper.start();
- * Dns dns = dnsHelper.getOptions().getService();
- * }
- * - *

After the test: - *

 {@code
- * dnsHelper.stop();
- * }
- */ -package com.google.cloud.dns.testing; diff --git a/google-cloud-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java b/google-cloud-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java deleted file mode 100644 index 6f98874b5a48..000000000000 --- a/google-cloud-dns/src/test/java/com/google/cloud/dns/testing/LocalDnsHelperTest.java +++ /dev/null @@ -1,2520 +0,0 @@ -/* - * Copyright 2016 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.cloud.dns.testing; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -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; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.Timeout; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class LocalDnsHelperTest { - - private static final String RRSET_TYPE = "A"; - private static final ResourceRecordSet RRSET1 = new ResourceRecordSet(); - private static final ResourceRecordSet RRSET2 = new ResourceRecordSet(); - private static final ResourceRecordSet RRSET_KEEP = new ResourceRecordSet(); - private static final String PROJECT_ID1 = "2135436541254"; - private static final String PROJECT_ID2 = "882248761325"; - private static final String ZONE_NAME1 = "my-little-zone"; - private static final String ZONE_NAME2 = "another-zone-name"; - private static final ManagedZone ZONE1 = new ManagedZone(); - private static final ManagedZone ZONE2 = new ManagedZone(); - private static final String DNS_NAME = "www.example.com."; - private static final Change CHANGE1 = new Change(); - private static final Change CHANGE2 = new Change(); - private static final Change CHANGE_KEEP = new Change(); - private static final Change CHANGE_COMPLEX = new Change(); - private static final LocalDnsHelper LOCAL_DNS_HELPER = LocalDnsHelper.create(0L); - private static final Map EMPTY_RPC_OPTIONS = ImmutableMap.of(); - private static final DnsRpc RPC = new DefaultDnsRpc(LOCAL_DNS_HELPER.getOptions()); - private static final String REAL_PROJECT_ID = LOCAL_DNS_HELPER.getOptions().getProjectId(); - 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); - ZONE1.setDescription(""); - ZONE1.setDnsName(DNS_NAME); - ZONE1.setNameServerSet("somenameserverset"); - ZONE2.setName(ZONE_NAME2); - ZONE2.setDescription(""); - ZONE2.setDnsName(DNS_NAME); - ZONE2.setNameServerSet("somenameserverset"); - RRSET1.setName(DNS_NAME); - RRSET1.setType(RRSET_TYPE); - RRSET1.setRrdatas(ImmutableList.of("1.1.1.1")); - RRSET2.setName(DNS_NAME); - RRSET2.setType(RRSET_TYPE); - RRSET2.setRrdatas(ImmutableList.of("123.132.153.156")); - RRSET_KEEP.setName(DNS_NAME); - RRSET_KEEP.setType("MX"); - RRSET_KEEP.setRrdatas(ImmutableList.of("255.255.255.254")); - CHANGE1.setAdditions(ImmutableList.of(RRSET1, RRSET2)); - CHANGE2.setDeletions(ImmutableList.of(RRSET2)); - CHANGE_KEEP.setAdditions(ImmutableList.of(RRSET_KEEP)); - CHANGE_COMPLEX.setAdditions(ImmutableList.of(RRSET_KEEP)); - CHANGE_COMPLEX.setDeletions(ImmutableList.of(RRSET_KEEP)); - LOCAL_DNS_HELPER.start(); - } - - @Rule - public Timeout globalTimeout = Timeout.seconds(60); - - @Before - public void setUp() { - resetProjects(); - optionsMap = new HashMap<>(); - } - - @AfterClass - public static void after() { - LOCAL_DNS_HELPER.stop(); - } - - private static void resetProjects() { - for (String project : LOCAL_DNS_HELPER.projects().keySet()) { - LOCAL_DNS_HELPER.projects().remove(project); - } - } - - @Test - public void testCreateZone() { - ManagedZone created = RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - // 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); - try { - RPC.create(null, EMPTY_RPC_OPTIONS); - fail("Zone cannot be null"); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("entity.managedZone")); - } - // create zone twice - try { - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - fail("Zone already exists."); - } catch (DnsException ex) { - // expected - assertEquals(409, ex.getCode()); - assertTrue(ex.getMessage().contains("already exists")); - } - // field options - resetProjects(); - Map options = new HashMap<>(); - options.put(DnsRpc.Option.FIELDS, "id"); - zone = RPC.create(ZONE1, options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNotNull(zone.getId()); - resetProjects(); - options.put(DnsRpc.Option.FIELDS, "creationTime"); - zone = RPC.create(ZONE1, options); - assertNotNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "dnsName"); - resetProjects(); - zone = RPC.create(ZONE1, options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNotNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "description"); - resetProjects(); - zone = RPC.create(ZONE1, options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNotNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "nameServers"); - resetProjects(); - zone = RPC.create(ZONE1, options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNotNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "nameServerSet"); - resetProjects(); - zone = RPC.create(ZONE1, options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNotNull(zone.getNameServerSet()); - assertNull(zone.getId()); - // several combined - options.put(DnsRpc.Option.FIELDS, "nameServerSet,description,id,name"); - resetProjects(); - zone = RPC.create(ZONE1, options); - assertNull(zone.getCreationTime()); - assertNotNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNotNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNotNull(zone.getNameServerSet()); - assertNotNull(zone.getId()); - } - - @Test - public void testGetZone() { - // non-existent - assertNull(RPC.getZone(ZONE_NAME1, EMPTY_RPC_OPTIONS)); - // existent - 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 - Map options = new HashMap<>(); - options.put(DnsRpc.Option.FIELDS, "id"); - zone = RPC.getZone(ZONE1.getName(), options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNotNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "creationTime"); - zone = RPC.getZone(ZONE1.getName(), options); - assertNotNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "dnsName"); - zone = RPC.getZone(ZONE1.getName(), options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNotNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "description"); - zone = RPC.getZone(ZONE1.getName(), options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNotNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "nameServers"); - zone = RPC.getZone(ZONE1.getName(), options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNotNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "nameServerSet"); - zone = RPC.getZone(ZONE1.getName(), options); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNotNull(zone.getNameServerSet()); - assertNull(zone.getId()); - // several combined - options.put(DnsRpc.Option.FIELDS, "nameServerSet,description,id,name"); - zone = RPC.getZone(ZONE1.getName(), options); - assertNull(zone.getCreationTime()); - assertNotNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNotNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNotNull(zone.getNameServerSet()); - assertNotNull(zone.getId()); - } - - @Test - public void testDeleteZone() { - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - assertTrue(RPC.deleteZone(ZONE1.getName())); - assertNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); - // deleting non-existent zone - assertFalse(RPC.deleteZone(ZONE1.getName())); - assertNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); - 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 in reverse order - assertTrue(RPC.deleteZone(ZONE1.getName())); - assertNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); - assertNotNull(RPC.getZone(ZONE2.getName(), EMPTY_RPC_OPTIONS)); - assertTrue(RPC.deleteZone(ZONE2.getName())); - assertNull(RPC.getZone(ZONE1.getName(), EMPTY_RPC_OPTIONS)); - assertNull(RPC.getZone(ZONE2.getName(), EMPTY_RPC_OPTIONS)); - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - RPC.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); - try { - RPC.deleteZone(ZONE1.getName()); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("not empty")); - } - } - - @Test - public void testCreateAndApplyChange() { - executeCreateAndApplyChangeTest(RPC); - } - - @Test - public void testCreateAndApplyChangeWithThreads() { - LocalDnsHelper localDnsThreaded = LocalDnsHelper.create(50L); - localDnsThreaded.start(); - DnsRpc rpc = new DefaultDnsRpc(localDnsThreaded.getOptions()); - executeCreateAndApplyChangeTest(rpc); - localDnsThreaded.stop(); - } - - private static void waitForChangeToComplete(DnsRpc rpc, String zoneName, String changeId) { - while (true) { - Change change = rpc.getChangeRequest(zoneName, changeId, EMPTY_RPC_OPTIONS); - if ("done".equals(change.getStatus())) { - return; - } - try { - Thread.sleep(50L); - } catch (InterruptedException e) { - fail("Thread was interrupted while waiting for change processing."); - } - } - } - - private static void executeCreateAndApplyChangeTest(DnsRpc rpc) { - rpc.create(ZONE1, EMPTY_RPC_OPTIONS); - assertNull(rpc.getChangeRequest(ZONE1.getName(), "1", EMPTY_RPC_OPTIONS)); - // add - Change createdChange = rpc.applyChangeRequest(ZONE1.getName(), CHANGE1, EMPTY_RPC_OPTIONS); - assertEquals(CHANGE1.getAdditions(), createdChange.getAdditions()); - assertEquals(CHANGE1.getDeletions(), createdChange.getDeletions()); - assertNotNull(createdChange.getStartTime()); - assertEquals("1", createdChange.getId()); - waitForChangeToComplete(rpc, ZONE1.getName(), "1"); // necessary for the following to return 409 - try { - rpc.applyChangeRequest(ZONE1.getName(), CHANGE1, EMPTY_RPC_OPTIONS); - fail(); - } catch (DnsException ex) { - assertEquals(409, ex.getCode()); - assertTrue(ex.getMessage().contains("already exists")); - } - assertNotNull(rpc.getChangeRequest(ZONE1.getName(), "1", EMPTY_RPC_OPTIONS)); - assertNull(rpc.getChangeRequest(ZONE1.getName(), "2", EMPTY_RPC_OPTIONS)); - // delete - rpc.applyChangeRequest(ZONE1.getName(), CHANGE2, EMPTY_RPC_OPTIONS); - assertNotNull(rpc.getChangeRequest(ZONE1.getName(), "1", EMPTY_RPC_OPTIONS)); - assertNotNull(rpc.getChangeRequest(ZONE1.getName(), "2", EMPTY_RPC_OPTIONS)); - waitForChangeToComplete(rpc, ZONE1.getName(), "2"); - rpc.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); - waitForChangeToComplete(rpc, ZONE1.getName(), "3"); - Iterable results = - rpc.listRecordSets(ZONE1.getName(), EMPTY_RPC_OPTIONS).results(); - List defaults = ImmutableList.of("SOA", "NS"); - boolean rrsetKeep = false; - boolean rrset1 = false; - for (ResourceRecordSet dnsRecord : results) { - if (dnsRecord.getName().equals(RRSET_KEEP.getName()) - && dnsRecord.getType().equals(RRSET_KEEP.getType())) { - rrsetKeep = true; - } else if (dnsRecord.getName().equals(RRSET1.getName()) - && dnsRecord.getType().equals(RRSET1.getType())) { - rrset1 = true; - } else if (!defaults.contains(dnsRecord.getType())) { - fail(String.format("Record with type %s should not exist", dnsRecord.getType())); - } - } - assertTrue(rrset1); - assertTrue(rrsetKeep); - } - - @Test - public void testGetProject() { - // 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)); - Project project = RPC.getProject(EMPTY_RPC_OPTIONS); - assertNotNull(project.getQuota()); - assertEquals(REAL_PROJECT_ID, project.getId()); - // fields options - Map options = new HashMap<>(); - options.put(DnsRpc.Option.FIELDS, "number"); - project = RPC.getProject(options); - assertNull(project.getId()); - assertNotNull(project.getNumber()); - assertNull(project.getQuota()); - options.put(DnsRpc.Option.FIELDS, "id"); - project = RPC.getProject(options); - assertNotNull(project.getId()); - assertNull(project.getNumber()); - assertNull(project.getQuota()); - options.put(DnsRpc.Option.FIELDS, "quota"); - project = RPC.getProject(options); - assertNull(project.getId()); - assertNull(project.getNumber()); - assertNotNull(project.getQuota()); - } - - @Test - public void testCreateChange() { - // non-existent zone - try { - RPC.applyChangeRequest(ZONE_NAME1, CHANGE1, EMPTY_RPC_OPTIONS); - fail("Zone was not created yet."); - } catch (DnsException ex) { - assertEquals(404, ex.getCode()); - } - // existent zone - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - assertNull(RPC.getChangeRequest(ZONE_NAME1, "1", EMPTY_RPC_OPTIONS)); - Change created = RPC.applyChangeRequest(ZONE1.getName(), CHANGE1, EMPTY_RPC_OPTIONS); - assertEquals(created, RPC.getChangeRequest(ZONE_NAME1, "1", EMPTY_RPC_OPTIONS)); - // field options - RPC.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); - Map options = new HashMap<>(); - options.put(DnsRpc.Option.FIELDS, "additions"); - Change complex = RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, options); - assertNotNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "deletions"); - complex = RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, options); - assertNull(complex.getAdditions()); - assertNotNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "id"); - complex = RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, options); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNotNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "startTime"); - complex = RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, options); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNotNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "status"); - complex = RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, options); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNotNull(complex.getStatus()); - } - - @Test - public void testGetChange() { - // existent - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - Change created = RPC.applyChangeRequest(ZONE1.getName(), CHANGE1, EMPTY_RPC_OPTIONS); - Change retrieved = RPC.getChangeRequest(ZONE1.getName(), "1", EMPTY_RPC_OPTIONS); - assertEquals(created, retrieved); - // non-existent - assertNull(RPC.getChangeRequest(ZONE1.getName(), "2", EMPTY_RPC_OPTIONS)); - // non-existent zone - try { - RPC.getChangeRequest(ZONE_NAME2, "1", EMPTY_RPC_OPTIONS); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(404, ex.getCode()); - assertTrue(ex.getMessage().contains("managedZone")); - } - // field options - RPC.applyChangeRequest(ZONE1.getName(), CHANGE_KEEP, EMPTY_RPC_OPTIONS); - Change change = RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, EMPTY_RPC_OPTIONS); - Map options = new HashMap<>(); - options.put(DnsRpc.Option.FIELDS, "additions"); - Change complex = RPC.getChangeRequest(ZONE1.getName(), change.getId(), options); - assertNotNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "deletions"); - complex = RPC.getChangeRequest(ZONE1.getName(), change.getId(), options); - assertNull(complex.getAdditions()); - assertNotNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "id"); - complex = RPC.getChangeRequest(ZONE1.getName(), change.getId(), options); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNotNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "startTime"); - complex = RPC.getChangeRequest(ZONE1.getName(), change.getId(), options); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNotNull(complex.getStartTime()); - assertNull(complex.getStatus()); - options.put(DnsRpc.Option.FIELDS, "status"); - complex = RPC.getChangeRequest(ZONE1.getName(), change.getId(), options); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNotNull(complex.getStatus()); - } - - @Test - public void testListZones() { - Iterable results = RPC.listZones(EMPTY_RPC_OPTIONS).results(); - ImmutableList zones = ImmutableList.copyOf(results); - assertEquals(0, zones.size()); - // some zones exists - ManagedZone created = RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - results = RPC.listZones(EMPTY_RPC_OPTIONS).results(); - zones = ImmutableList.copyOf(results); - assertEquals(created, zones.get(0)); - assertEquals(1, zones.size()); - created = RPC.create(ZONE2, EMPTY_RPC_OPTIONS); - results = RPC.listZones(EMPTY_RPC_OPTIONS).results(); - zones = ImmutableList.copyOf(results); - assertEquals(2, zones.size()); - assertTrue(zones.contains(created)); - // error in options - Map options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, 0); - try { - RPC.listZones(options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.maxResults")); - } - options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, -1); - try { - RPC.listZones(options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.maxResults")); - } - // ok size - options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, 335); - results = RPC.listZones(options).results(); - zones = ImmutableList.copyOf(results); - assertEquals(2, zones.size()); - // dns name problems - options = new HashMap<>(); - options.put(DnsRpc.Option.DNS_NAME, "aaa"); - try { - RPC.listZones(options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.dnsName")); - } - // ok name - options = new HashMap<>(); - options.put(DnsRpc.Option.DNS_NAME, "aaaa."); - results = RPC.listZones(options).results(); - zones = ImmutableList.copyOf(results); - assertEquals(0, zones.size()); - // field options - options = new HashMap<>(); - options.put(DnsRpc.Option.FIELDS, "managedZones(id)"); - ManagedZone zone = RPC.listZones(options).results().iterator().next(); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNotNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "managedZones(creationTime)"); - zone = RPC.listZones(options).results().iterator().next(); - assertNotNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "managedZones(dnsName)"); - zone = RPC.listZones(options).results().iterator().next(); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNotNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "managedZones(description)"); - zone = RPC.listZones(options).results().iterator().next(); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNotNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "managedZones(nameServers)"); - zone = RPC.listZones(options).results().iterator().next(); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNotNull(zone.getNameServers()); - assertNull(zone.getNameServerSet()); - assertNull(zone.getId()); - options.put(DnsRpc.Option.FIELDS, "managedZones(nameServerSet)"); - DnsRpc.ListResult listResult = RPC.listZones(options); - zone = listResult.results().iterator().next(); - assertNull(listResult.pageToken()); - assertNull(zone.getCreationTime()); - assertNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNotNull(zone.getNameServerSet()); - assertNull(zone.getId()); - // several combined - options.put(DnsRpc.Option.FIELDS, - "managedZones(nameServerSet,description,id,name),nextPageToken"); - options.put(DnsRpc.Option.PAGE_SIZE, 1); - listResult = RPC.listZones(options); - zone = listResult.results().iterator().next(); - assertNull(zone.getCreationTime()); - assertNotNull(zone.getName()); - assertNull(zone.getDnsName()); - assertNotNull(zone.getDescription()); - assertNull(zone.getNameServers()); - assertNotNull(zone.getNameServerSet()); - assertNotNull(zone.getId()); - assertEquals(zone.getName(), listResult.pageToken()); - } - - @Test - public void testListRecordSets() { - // no zone exists - try { - RPC.listRecordSets(ZONE_NAME1, EMPTY_RPC_OPTIONS); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(404, ex.getCode()); - assertTrue(ex.getMessage().contains("managedZone")); - } - // zone exists but has no records - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - Iterable results = - RPC.listRecordSets(ZONE_NAME1, EMPTY_RPC_OPTIONS).results(); - ImmutableList records = ImmutableList.copyOf(results); - assertEquals(2, records.size()); // contains default NS and SOA - // zone has records - RPC.applyChangeRequest(ZONE_NAME1, CHANGE_KEEP, EMPTY_RPC_OPTIONS); - results = RPC.listRecordSets(ZONE_NAME1, EMPTY_RPC_OPTIONS).results(); - records = ImmutableList.copyOf(results); - assertEquals(3, records.size()); - // error in options - Map options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, 0); - try { - RPC.listRecordSets(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.maxResults")); - } - options.put(DnsRpc.Option.PAGE_SIZE, -1); - try { - RPC.listRecordSets(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.maxResults")); - } - options.put(DnsRpc.Option.PAGE_SIZE, 15); - results = RPC.listRecordSets(ZONE1.getName(), options).results(); - records = ImmutableList.copyOf(results); - assertEquals(3, records.size()); - // dnsName filter - options = new HashMap<>(); - options.put(DnsRpc.Option.NAME, "aaa"); - try { - RPC.listRecordSets(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.name")); - } - options.put(DnsRpc.Option.NAME, "aaa."); - results = RPC.listRecordSets(ZONE1.getName(), options).results(); - records = ImmutableList.copyOf(results); - assertEquals(0, records.size()); - options.put(DnsRpc.Option.NAME, null); - options.put(DnsRpc.Option.DNS_TYPE, "A"); - try { - RPC.listRecordSets(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.name")); - } - options.put(DnsRpc.Option.NAME, "aaa."); - options.put(DnsRpc.Option.DNS_TYPE, "a"); - try { - RPC.listRecordSets(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.type")); - } - options.put(DnsRpc.Option.NAME, DNS_NAME); - options.put(DnsRpc.Option.DNS_TYPE, "SOA"); - results = RPC.listRecordSets(ZONE1.getName(), options).results(); - records = ImmutableList.copyOf(results); - assertEquals(1, records.size()); - // field options - options = new HashMap<>(); - options.put(DnsRpc.Option.FIELDS, "rrsets(name)"); - DnsRpc.ListResult listResult = - RPC.listRecordSets(ZONE1.getName(), options); - records = ImmutableList.copyOf(listResult.results()); - ResourceRecordSet record = records.get(0); - assertNotNull(record.getName()); - assertNull(record.getRrdatas()); - assertNull(record.getType()); - assertNull(record.getTtl()); - assertNull(listResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "rrsets(rrdatas)"); - listResult = RPC.listRecordSets(ZONE1.getName(), options); - records = ImmutableList.copyOf(listResult.results()); - record = records.get(0); - assertNull(record.getName()); - assertNotNull(record.getRrdatas()); - assertNull(record.getType()); - assertNull(record.getTtl()); - assertNull(listResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "rrsets(ttl)"); - listResult = RPC.listRecordSets(ZONE1.getName(), options); - records = ImmutableList.copyOf(listResult.results()); - record = records.get(0); - assertNull(record.getName()); - assertNull(record.getRrdatas()); - assertNull(record.getType()); - assertNotNull(record.getTtl()); - assertNull(listResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "rrsets(type)"); - listResult = RPC.listRecordSets(ZONE1.getName(), options); - records = ImmutableList.copyOf(listResult.results()); - record = records.get(0); - assertNull(record.getName()); - assertNull(record.getRrdatas()); - assertNotNull(record.getType()); - assertNull(record.getTtl()); - assertNull(listResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "nextPageToken"); - listResult = RPC.listRecordSets(ZONE1.getName(), options); - records = ImmutableList.copyOf(listResult.results()); - record = records.get(0); - assertNull(record.getName()); - assertNull(record.getRrdatas()); - assertNull(record.getType()); - assertNull(record.getTtl()); - assertNull(listResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "nextPageToken,rrsets(name,rrdatas)"); - options.put(DnsRpc.Option.PAGE_SIZE, 1); - listResult = RPC.listRecordSets(ZONE1.getName(), options); - records = ImmutableList.copyOf(listResult.results()); - assertEquals(1, records.size()); - record = records.get(0); - assertNotNull(record.getName()); - assertNotNull(record.getRrdatas()); - assertNull(record.getType()); - assertNull(record.getTtl()); - assertNotNull(listResult.pageToken()); - } - - @Test - public void testListChanges() { - // no such zone exists - try { - RPC.listChangeRequests(ZONE_NAME1, EMPTY_RPC_OPTIONS); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(404, ex.getCode()); - assertTrue(ex.getMessage().contains("managedZone")); - } - // zone exists but has no changes - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - Iterable results = RPC.listChangeRequests(ZONE1.getName(), EMPTY_RPC_OPTIONS).results(); - ImmutableList changes = ImmutableList.copyOf(results); - assertEquals(1, changes.size()); - // 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); - results = RPC.listChangeRequests(ZONE1.getName(), EMPTY_RPC_OPTIONS).results(); - changes = ImmutableList.copyOf(results); - assertEquals(4, changes.size()); - // error in options - Map options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, 0); - try { - RPC.listChangeRequests(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.maxResults")); - } - options.put(DnsRpc.Option.PAGE_SIZE, -1); - try { - RPC.listChangeRequests(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.maxResults")); - } - options.put(DnsRpc.Option.PAGE_SIZE, 15); - results = RPC.listChangeRequests(ZONE1.getName(), options).results(); - changes = ImmutableList.copyOf(results); - assertEquals(4, changes.size()); - options = new HashMap<>(); - options.put(DnsRpc.Option.SORTING_ORDER, "descending"); - results = RPC.listChangeRequests(ZONE1.getName(), options).results(); - ImmutableList descending = ImmutableList.copyOf(results); - results = RPC.listChangeRequests(ZONE1.getName(), EMPTY_RPC_OPTIONS).results(); - ImmutableList ascending = ImmutableList.copyOf(results); - int size = 4; - assertEquals(size, descending.size()); - for (int i = 0; i < size; i++) { - assertEquals(descending.get(i), ascending.get(size - i - 1)); - } - options.put(DnsRpc.Option.SORTING_ORDER, "something else"); - try { - RPC.listChangeRequests(ZONE1.getName(), options); - fail(); - } catch (DnsException ex) { - // expected - assertEquals(400, ex.getCode()); - assertTrue(ex.getMessage().contains("parameters.sortOrder")); - } - // field options - RPC.applyChangeRequest(ZONE1.getName(), CHANGE_COMPLEX, EMPTY_RPC_OPTIONS); - options = new HashMap<>(); - options.put(DnsRpc.Option.SORTING_ORDER, "descending"); - options.put(DnsRpc.Option.FIELDS, "changes(additions)"); - DnsRpc.ListResult changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - changes = ImmutableList.copyOf(changeListResult.results()); - Change complex = changes.get(0); - assertNotNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - assertNull(changeListResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "changes(deletions)"); - changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - changes = ImmutableList.copyOf(changeListResult.results()); - complex = changes.get(0); - assertNull(complex.getAdditions()); - assertNotNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - assertNull(changeListResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "changes(id)"); - changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - changes = ImmutableList.copyOf(changeListResult.results()); - complex = changes.get(0); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNotNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - assertNull(changeListResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "changes(startTime)"); - changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - changes = ImmutableList.copyOf(changeListResult.results()); - complex = changes.get(0); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNotNull(complex.getStartTime()); - assertNull(complex.getStatus()); - assertNull(changeListResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "changes(status)"); - changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - changes = ImmutableList.copyOf(changeListResult.results()); - complex = changes.get(0); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNotNull(complex.getStatus()); - assertNull(changeListResult.pageToken()); - options.put(DnsRpc.Option.FIELDS, "nextPageToken"); - options.put(DnsRpc.Option.PAGE_SIZE, 1); - changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - changes = ImmutableList.copyOf(changeListResult.results()); - complex = changes.get(0); - assertNull(complex.getAdditions()); - assertNull(complex.getDeletions()); - assertNull(complex.getId()); - assertNull(complex.getStartTime()); - assertNull(complex.getStatus()); - assertNotNull(changeListResult.pageToken()); - } - - @Test - public void testDnsRecordPaging() { - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - List complete = ImmutableList.copyOf( - RPC.listRecordSets(ZONE1.getName(), EMPTY_RPC_OPTIONS).results()); - Map options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, 1); - DnsRpc.ListResult listResult = RPC.listRecordSets(ZONE1.getName(), options); - ImmutableList records = ImmutableList.copyOf(listResult.results()); - assertEquals(1, records.size()); - assertEquals(complete.get(0), records.get(0)); - options.put(DnsRpc.Option.PAGE_TOKEN, listResult.pageToken()); - listResult = RPC.listRecordSets(ZONE1.getName(), options); - records = ImmutableList.copyOf(listResult.results()); - assertEquals(1, records.size()); - assertEquals(complete.get(1), records.get(0)); - } - - @Test - public void testZonePaging() { - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - RPC.create(ZONE2, EMPTY_RPC_OPTIONS); - ImmutableList complete = ImmutableList.copyOf( - RPC.listZones(EMPTY_RPC_OPTIONS).results()); - Map options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, 1); - DnsRpc.ListResult listResult = RPC.listZones(options); - ImmutableList page1 = ImmutableList.copyOf(listResult.results()); - assertEquals(1, page1.size()); - assertEquals(complete.get(0), page1.get(0)); - assertEquals(page1.get(0).getName(), listResult.pageToken()); - options.put(DnsRpc.Option.PAGE_TOKEN, listResult.pageToken()); - listResult = RPC.listZones(options); - ImmutableList page2 = ImmutableList.copyOf(listResult.results()); - assertEquals(1, page2.size()); - assertEquals(complete.get(1), page2.get(0)); - assertNull(listResult.pageToken()); - } - - @Test - public void testChangePaging() { - RPC.create(ZONE1, EMPTY_RPC_OPTIONS); - 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); - ImmutableList complete = - ImmutableList.copyOf(RPC.listChangeRequests(ZONE1.getName(), EMPTY_RPC_OPTIONS).results()); - Map options = new HashMap<>(); - options.put(DnsRpc.Option.PAGE_SIZE, 1); - DnsRpc.ListResult changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - List changes = ImmutableList.copyOf(changeListResult.results()); - assertEquals(1, changes.size()); - assertEquals(complete.get(0), changes.get(0)); - assertEquals(complete.get(0).getId(), changeListResult.pageToken()); - options.put(DnsRpc.Option.PAGE_TOKEN, changeListResult.pageToken()); - changeListResult = RPC.listChangeRequests(ZONE1.getName(), options); - changes = ImmutableList.copyOf(changeListResult.results()); - assertEquals(1, changes.size()); - assertEquals(complete.get(1), changes.get(0)); - assertEquals(complete.get(1).getId(), changeListResult.pageToken()); - } - - @Test - public void testToListResponse() { - LocalDnsHelper.Response response = LocalDnsHelper.toListResponse( - Lists.newArrayList("some", "multiple", "words"), "contextA", "IncludeThisPageToken", true); - assertTrue(response.body().contains("IncludeThisPageToken")); - assertTrue(response.body().contains("contextA")); - response = LocalDnsHelper.toListResponse( - Lists.newArrayList("some", "multiple", "words"), "contextB", "IncludeThisPageToken", false); - assertFalse(response.body().contains("IncludeThisPageToken")); - assertTrue(response.body().contains("contextB")); - response = LocalDnsHelper.toListResponse( - Lists.newArrayList("some", "multiple", "words"), "contextC", null, true); - assertFalse(response.body().contains("pageToken")); - assertTrue(response.body().contains("contextC")); - } - - @Test - public void testCreateZoneValidation() { - ManagedZone minimalZone = copyZone(ZONE1); - // no name - ManagedZone copy = copyZone(minimalZone); - copy.setName(null); - LocalDnsHelper.Response response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.name")); - // no description - copy = copyZone(minimalZone); - copy.setDescription(null); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.description")); - // no dns name - copy = copyZone(minimalZone); - copy.setDnsName(null); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.dnsName")); - // zone name does not start with a letter - copy = copyZone(minimalZone); - copy.setName("1aaaaaa"); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.name")); - assertTrue(response.body().contains("Invalid")); - // zone name is too long - copy = copyZone(minimalZone); - copy.setName("123456aaaa123456aaaa123456aaaa123456aaaa123456aaaa123456aaaa123456aaaa123456aa"); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.name")); - assertTrue(response.body().contains("Invalid")); - // zone name contains invalid characters - copy = copyZone(minimalZone); - copy.setName("x1234AA6aa"); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.name")); - assertTrue(response.body().contains("Invalid")); - // zone name contains invalid characters - copy = copyZone(minimalZone); - copy.setName("x a"); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.name")); - assertTrue(response.body().contains("Invalid")); - // dns name does not end with period - copy = copyZone(minimalZone); - copy.setDnsName("aaaaaa.com"); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("entity.managedZone.dnsName")); - assertTrue(response.body().contains("Invalid")); - // dns name is reserved - copy = copyZone(minimalZone); - copy.setDnsName("com."); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(400, response.code()); - assertTrue(response.body().contains("not available to be created.")); - // empty description should pass - copy = copyZone(minimalZone); - copy.setDescription(""); - response = LOCAL_DNS_HELPER.createZone(PROJECT_ID1, copy); - assertEquals(200, response.code()); - } - - @Test - public void testCheckListOptions() { - // listing zones - optionsMap.put("maxResults", "-1"); - LocalDnsHelper.Response response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("parameters.maxResults")); - optionsMap.put("maxResults", "0"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("parameters.maxResults")); - optionsMap.put("maxResults", "aaaa"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("integer")); - optionsMap.put("maxResults", "15"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - optionsMap.put("dnsName", "aaa"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("parameters.dnsName")); - optionsMap.put("dnsName", "aaa."); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - // listing dns records - optionsMap.put("name", "aaa"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("parameters.name")); - optionsMap.put("name", "aaa."); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - optionsMap.put("name", null); - optionsMap.put("type", "A"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("parameters.name")); - optionsMap.put("name", "aaa."); - optionsMap.put("type", "a"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("parameters.type")); - optionsMap.put("name", "aaaa."); - optionsMap.put("type", "A"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - // listing changes - optionsMap.put("sortBy", "changeSequence"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - optionsMap.put("sortBy", "something else"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("Allowed values: [changesequence]")); - optionsMap.put("sortBy", "ChAnGeSeQuEnCe"); // is not case sensitive - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - optionsMap.put("sortOrder", "ascending"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - optionsMap.put("sortOrder", "descending"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertNull(response); - optionsMap.put("sortOrder", "somethingelse"); - response = LocalDnsHelper.checkListOptions(optionsMap); - assertEquals(400, response.code()); - assertTrue(response.body().contains("parameters.sortOrder")); - } - - @Test - public void testCheckRrset() { - ResourceRecordSet valid = new ResourceRecordSet(); - valid.setName(ZONE1.getDnsName()); - valid.setType("A"); - valid.setRrdatas(ImmutableList.of("0.255.1.5")); - valid.setTtl(500); - Change validChange = new Change(); - validChange.setAdditions(ImmutableList.of(valid)); - LOCAL_DNS_HELPER.createZone(PROJECT_ID1, ZONE1); - LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, validChange); - // delete with field mismatch - LocalDnsHelper.ZoneContainer zone = LOCAL_DNS_HELPER.findZone(PROJECT_ID1, ZONE_NAME1); - valid.setTtl(valid.getTtl() + 20); - LocalDnsHelper.Response response = LocalDnsHelper.checkRrset(valid, zone, 0, "deletions"); - assertEquals(412, response.code()); - assertTrue(response.body().contains("entity.change.deletions[0]")); - } - - @Test - public void testCheckRrdata() { - // A - assertTrue(LocalDnsHelper.checkRrData("255.255.255.255", "A")); - assertTrue(LocalDnsHelper.checkRrData("13.15.145.165", "A")); - assertTrue(LocalDnsHelper.checkRrData("0.0.0.0", "A")); - assertFalse(LocalDnsHelper.checkRrData("255.255.255.256", "A")); - assertFalse(LocalDnsHelper.checkRrData("-1.255.255.255", "A")); - assertFalse(LocalDnsHelper.checkRrData(".255.255.254", "A")); - assertFalse(LocalDnsHelper.checkRrData("111.255.255.", "A")); - assertFalse(LocalDnsHelper.checkRrData("111.255..22", "A")); - assertFalse(LocalDnsHelper.checkRrData("111.255.aa.22", "A")); - assertFalse(LocalDnsHelper.checkRrData("", "A")); - assertFalse(LocalDnsHelper.checkRrData("...", "A")); - assertFalse(LocalDnsHelper.checkRrData("111.255.12", "A")); - assertFalse(LocalDnsHelper.checkRrData("111.255.12.11.11", "A")); - // AAAA - assertTrue(LocalDnsHelper.checkRrData("1F:fa:09fd::343:aaaa:AAAA:0", "AAAA")); - assertTrue(LocalDnsHelper.checkRrData("0000:FFFF:09fd::343:aaaa:AAAA:0", "AAAA")); - assertFalse(LocalDnsHelper.checkRrData("-2:::::::", "AAAA")); - assertTrue(LocalDnsHelper.checkRrData("0::0", "AAAA")); - assertFalse(LocalDnsHelper.checkRrData("::1FFFF:::::", "AAAA")); - assertFalse(LocalDnsHelper.checkRrData("::aqaa:::::", "AAAA")); - assertFalse(LocalDnsHelper.checkRrData("::::::::", "AAAA")); // too long - assertFalse(LocalDnsHelper.checkRrData("::::::", "AAAA")); // too short - } - - @Test - public void testCheckChange() { - ResourceRecordSet validA = new ResourceRecordSet(); - validA.setName(ZONE1.getDnsName()); - validA.setType("A"); - validA.setRrdatas(ImmutableList.of("0.255.1.5")); - ResourceRecordSet invalidA = new ResourceRecordSet(); - invalidA.setName(ZONE1.getDnsName()); - invalidA.setType("A"); - invalidA.setRrdatas(ImmutableList.of("0.-255.1.5")); - Change validChange = new Change(); - validChange.setAdditions(ImmutableList.of(validA)); - Change invalidChange = new Change(); - invalidChange.setAdditions(ImmutableList.of(invalidA)); - LocalDnsHelper.ZoneContainer zoneContainer = new LocalDnsHelper.ZoneContainer(ZONE1); - LocalDnsHelper.Response response = LocalDnsHelper.checkChange(validChange, zoneContainer); - assertNull(response); - response = LocalDnsHelper.checkChange(invalidChange, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains("additions[0].rrdata[0]")); - // only empty additions/deletions - Change empty = new Change(); - empty.setAdditions(ImmutableList.of()); - empty.setDeletions(ImmutableList.of()); - response = LocalDnsHelper.checkChange(empty, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains( - "The 'entity.change' parameter is required but was missing.")); - // null additions/deletions - empty = new Change(); - response = LocalDnsHelper.checkChange(empty, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains( - "The 'entity.change' parameter is required but was missing.")); - // non-matching name - validA.setName(ZONE1.getDnsName() + ".aaa."); - response = LocalDnsHelper.checkChange(validChange, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains("additions[0].name")); - // wrong type - validA.setName(ZONE1.getDnsName()); // revert - validA.setType("ABCD"); - response = LocalDnsHelper.checkChange(validChange, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains("additions[0].type")); - // wrong ttl - validA.setType("A"); // revert - validA.setTtl(-1); - response = LocalDnsHelper.checkChange(validChange, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains("additions[0].ttl")); - validA.setTtl(null); - // null name - validA.setName(null); - response = LocalDnsHelper.checkChange(validChange, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains("additions[0].name")); - validA.setName(ZONE1.getDnsName()); - // null type - validA.setType(null); - response = LocalDnsHelper.checkChange(validChange, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains("additions[0].type")); - validA.setType("A"); - // null rrdata - final List temp = validA.getRrdatas(); // preserve - validA.setRrdatas(null); - response = LocalDnsHelper.checkChange(validChange, zoneContainer); - assertEquals(400, response.code()); - assertTrue(response.body().contains("additions[0].rrdata")); - validA.setRrdatas(temp); - // delete non-existent - ResourceRecordSet nonExistent = new ResourceRecordSet(); - nonExistent.setName(ZONE1.getDnsName()); - nonExistent.setType("AAAA"); - nonExistent.setRrdatas(ImmutableList.of("0:0:0:0:5::6")); - Change delete = new Change(); - delete.setDeletions(ImmutableList.of(nonExistent)); - response = LocalDnsHelper.checkChange(delete, zoneContainer); - assertEquals(404, response.code()); - assertTrue(response.body().contains("deletions[0]")); - } - - @Test - public void testCheckAdditionsDeletions() { - ResourceRecordSet validA = new ResourceRecordSet(); - validA.setName(ZONE1.getDnsName()); - validA.setType("A"); - validA.setRrdatas(ImmutableList.of("0.255.1.5")); - Change validChange = new Change(); - validChange.setAdditions(ImmutableList.of(validA)); - LOCAL_DNS_HELPER.createZone(PROJECT_ID1, ZONE1); - LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, validChange); - LocalDnsHelper.ZoneContainer container = LOCAL_DNS_HELPER.findZone(PROJECT_ID1, ZONE_NAME1); - LocalDnsHelper.Response response = - LocalDnsHelper.checkAdditionsDeletions(ImmutableList.of(validA), null, container); - assertEquals(409, response.code()); - assertTrue(response.body().contains("already exists")); - } - - @Test - public void testCreateChangeContentValidation() { - ResourceRecordSet validA = new ResourceRecordSet(); - validA.setName(ZONE1.getDnsName()); - validA.setType("A"); - validA.setRrdatas(ImmutableList.of("0.255.1.5")); - Change validChange = new Change(); - validChange.setAdditions(ImmutableList.of(validA)); - LOCAL_DNS_HELPER.createZone(PROJECT_ID1, ZONE1); - LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, validChange); - LocalDnsHelper.Response response = - LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, validChange); - assertEquals(409, response.code()); - assertTrue(response.body().contains("already exists")); - // delete with field mismatch - Change delete = new Change(); - validA.setTtl(20); // mismatch - delete.setDeletions(ImmutableList.of(validA)); - response = LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, delete); - assertEquals(412, response.code()); - assertTrue(response.body().contains("entity.change.deletions[0]")); - // delete and add SOA - Change addition = new Change(); - ImmutableCollection dnsRecords = - LOCAL_DNS_HELPER.findZone(PROJECT_ID1, ZONE_NAME1).dnsRecords().get().values(); - LinkedList deletions = new LinkedList<>(); - LinkedList additions = new LinkedList<>(); - for (ResourceRecordSet rrset : dnsRecords) { - if (rrset.getType().equals("SOA")) { - deletions.add(rrset); - ResourceRecordSet copy = copyRrset(rrset); - copy.setName("x." + copy.getName()); - additions.add(copy); - break; - } - } - delete.setDeletions(deletions); - addition.setAdditions(additions); - response = LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, delete); - assertEquals(400, response.code()); - assertTrue(response.body().contains( - "zone must contain exactly one resource record set of type 'SOA' at the apex")); - assertTrue(response.body().contains("deletions[0]")); - response = LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, addition); - assertEquals(400, response.code()); - assertTrue(response.body().contains( - "zone must contain exactly one resource record set of type 'SOA' at the apex")); - assertTrue(response.body().contains("additions[0]")); - // delete NS - deletions = new LinkedList<>(); - additions = new LinkedList<>(); - for (ResourceRecordSet rrset : dnsRecords) { - if (rrset.getType().equals("NS")) { - deletions.add(rrset); - ResourceRecordSet copy = copyRrset(rrset); - copy.setName("x." + copy.getName()); - additions.add(copy); - break; - } - } - delete.setDeletions(deletions); - addition.setAdditions(additions); - response = LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, delete); - assertEquals(400, response.code()); - assertTrue(response.body().contains( - "zone must contain exactly one resource record set of type 'NS' at the apex")); - response = LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, addition); - assertEquals(400, response.code()); - assertTrue(response.body().contains( - "zone must contain exactly one resource record set of type 'NS' at the apex")); - assertTrue(response.body().contains("additions[0]")); - // change (delete + add) - addition.setDeletions(deletions); - response = LOCAL_DNS_HELPER.createChange(PROJECT_ID1, ZONE_NAME1, addition); - assertEquals(200, response.code()); - } - - @Test - public void testMatchesCriteria() { - assertTrue(LocalDnsHelper.matchesCriteria(RRSET1, RRSET1.getName(), RRSET1.getType())); - assertFalse(LocalDnsHelper.matchesCriteria(RRSET1, RRSET1.getName(), "anothertype")); - assertTrue(LocalDnsHelper.matchesCriteria(RRSET1, null, RRSET1.getType())); - assertTrue(LocalDnsHelper.matchesCriteria(RRSET1, RRSET1.getName(), null)); - assertFalse(LocalDnsHelper.matchesCriteria(RRSET1, "anothername", RRSET1.getType())); - } - - @Test - public void testGetUniqueId() { - assertNotNull(LocalDnsHelper.getUniqueId(new HashSet())); - } - - @Test - public void testRandomNameServers() { - assertEquals(4, LocalDnsHelper.randomNameservers().size()); - } - - private static ManagedZone copyZone(ManagedZone original) { - ManagedZone copy = new ManagedZone(); - copy.setDescription(original.getDescription()); - copy.setName(original.getName()); - copy.setCreationTime(original.getCreationTime()); - copy.setId(original.getId()); - copy.setNameServerSet(original.getNameServerSet()); - copy.setDnsName(original.getDnsName()); - if (original.getNameServers() != null) { - copy.setNameServers(ImmutableList.copyOf(original.getNameServers())); - } - return copy; - } - - private static ResourceRecordSet copyRrset(ResourceRecordSet set) { - ResourceRecordSet copy = new ResourceRecordSet(); - if (set.getRrdatas() != null) { - copy.setRrdatas(ImmutableList.copyOf(set.getRrdatas())); - } - copy.setTtl(set.getTtl()); - copy.setName(set.getName()); - 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(); - batch.addListChangeRequests(ZONE_NAME1, new SuccessExpectedCallback() { - @Override - public void onSuccess(ChangesListResponse response) { - List changes = response.getChanges(); - for (int i = 0; i < 4; 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 < 4; i++) { - assertEquals(Iterables.get(descending, i), changes.get(3 - i)); - } - } - }, 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(); - } -}