diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java index a3fdaa6e4f..1dc9e06dd5 100644 --- a/providers/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/DynECTApi.java @@ -30,6 +30,8 @@ import javax.ws.rs.PathParam; import org.jclouds.Fallbacks.NullOnNotFoundOr404; import org.jclouds.dynect.v3.domain.Job; +import org.jclouds.dynect.v3.features.GeoRegionGroupApi; +import org.jclouds.dynect.v3.features.GeoServiceApi; import org.jclouds.dynect.v3.features.RecordApi; import org.jclouds.dynect.v3.features.SessionApi; import org.jclouds.dynect.v3.features.ZoneApi; @@ -67,20 +69,32 @@ public interface DynECTApi extends Closeable { Job getJob(@PathParam("jobId") long jobId); /** - * Provides synchronous access to Session features. + * Provides access to Session features. */ @Delegate SessionApi getSessionApi(); /** - * Provides synchronous access to Zone features. + * Provides access to Zone features. */ @Delegate ZoneApi getZoneApi(); /** - * Provides synchronous access to Record features + * Provides access to Record features */ @Delegate RecordApi getRecordApiForZone(@PathParam("zone") String zone); + + /** + * Provides access to Geo features. + */ + @Delegate + GeoServiceApi getGeoServiceApi(); + + /** + * Provides access to Geo region group features + */ + @Delegate + GeoRegionGroupApi getGeoRegionGroupApiForService(@PathParam("serviceName") String serviceName); } diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTParserModule.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTParserModule.java index 9d52117038..748c5626b6 100644 --- a/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTParserModule.java +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/config/DynECTParserModule.java @@ -19,15 +19,27 @@ package org.jclouds.dynect.v3.config; import java.lang.reflect.Type; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import javax.inject.Singleton; +import org.jclouds.dynect.v3.domain.GeoService; +import org.jclouds.dynect.v3.domain.Node; +import org.jclouds.dynect.v3.domain.RecordSet; +import org.jclouds.dynect.v3.domain.RecordSet.Value; +import org.jclouds.dynect.v3.domain.RecordSet.Value.Builder; +import org.jclouds.dynect.v3.domain.GeoRegionGroup; import org.jclouds.dynect.v3.domain.SessionCredentials; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; import com.google.inject.AbstractModule; @@ -46,8 +58,9 @@ public class DynECTParserModule extends AbstractModule { @Singleton public Map provideCustomAdapterBindings() { return new ImmutableMap.Builder() - .put(SessionCredentials.class, new SessionCredentialsTypeAdapter()) - .build(); + .put(SessionCredentials.class, new SessionCredentialsTypeAdapter()) + .put(GeoRegionGroup.class, new GeoRegionGroupTypeAdapter()) + .put(GeoService.class, new GeoServiceTypeAdapter()).build(); } private static class SessionCredentialsTypeAdapter implements JsonSerializer { @@ -59,4 +72,87 @@ public class DynECTParserModule extends AbstractModule { return metadataObject; } } + + private static class GeoRegionGroupTypeAdapter implements JsonDeserializer { + + @Override + public GeoRegionGroup deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + CreepyGeoRegionGroup creepyGeoRegionGroup = context.deserialize(json, CreepyGeoRegionGroup.class); + GeoRegionGroup.Builder builder = GeoRegionGroup.builder(); + builder.name(creepyGeoRegionGroup.name); + builder.serviceName(creepyGeoRegionGroup.service_name); + builder.countries(creepyGeoRegionGroup.countries); + ImmutableList.Builder rsets = ImmutableList.builder(); + for (Entry>> entry : creepyGeoRegionGroup.rdata.entrySet()) { + if (entry.getValue().isEmpty()) + continue; + // ex. spf_rdata -> SPF + String type = entry.getKey().substring(0, entry.getKey().indexOf('_')).toUpperCase(); + // ex. dhcid_ttl + int ttl = creepyGeoRegionGroup.ttl.get(type.toLowerCase() + "_ttl"); + RecordSet.Builder rset = RecordSet.builder(); + rset.type(type); + rset.ttl(ttl); + + // weight is only present for a couple record types + List weights = creepyGeoRegionGroup.weight.get(type.toLowerCase() + "_weight"); + if (weights == null) + weights = ImmutableList.of(); + + List labels = creepyGeoRegionGroup.label.get(type.toLowerCase() + "_label"); + for (int i = 0; i < entry.getValue().size(); i++) { + Builder elementBuilder = Value.builder().rdata(entry.getValue().get(i)); + // chance of index out of bounds + if (i < labels.size()) + elementBuilder.label(labels.get(i)); + if (i < weights.size()) + elementBuilder.weight(weights.get(i)); + rset.add(elementBuilder.build()); + } + rsets.add(rset.build()); + } + builder.recordSets(rsets.build()); + return builder.build(); + } + } + + private static class CreepyGeoRegionGroup { + String name; + // aaaa_weight + Map> weight; + List countries; + String service_name; + // spf_rdata + Map>> rdata; + // a_label + Map> label; + // dhcid_ttl + Map ttl; + } + + + private static class GeoServiceTypeAdapter implements JsonDeserializer { + + @Override + public GeoService deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + CreepyGeoService creepyGeoService = context.deserialize(json, CreepyGeoService.class); + GeoService.Builder builder = GeoService.builder(); + builder.name(creepyGeoService.name); + builder.active("Y".equals(creepyGeoService.active)); + builder.ttl(creepyGeoService.ttl); + builder.nodes(creepyGeoService.nodes); + builder.groups(creepyGeoService.groups); + return builder.build(); + } + } + + private static class CreepyGeoService { + String name; + String active;// creepy part + int ttl; + List nodes; + List groups; + } } diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/GeoRegionGroup.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/GeoRegionGroup.java new file mode 100644 index 0000000000..97712c1b69 --- /dev/null +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/GeoRegionGroup.java @@ -0,0 +1,193 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, String 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +/** + * @author Adrian Cole + */ +public class GeoRegionGroup { + + private final Optional serviceName; + private final String name; + private final List countries; + private final List recordSets; + + private GeoRegionGroup(Optional serviceName, String name, List countries, List recordSets) { + this.serviceName = checkNotNull(serviceName, "serviceName"); + this.name = checkNotNull(name, "name"); + this.countries = checkNotNull(countries, "countries of %s/%s", serviceName, name); + this.recordSets = checkNotNull(recordSets, "recordSets of %s", name); + } + + /** + * Name of the Geo Service. Absent, if a member of {@link GeoService} + */ + public Optional getServiceName() { + return serviceName; + } + + /** + * Name of the Region Group + */ + public String getName() { + return name; + } + + /** + * A list of ISO-3166 two letter codes to represent the names of countries + * and their subdivisions or one of the predefined groups. + */ + public List getCountries() { + return countries; + } + + /** + * record sets assigned to this region group. + */ + public List getRecordSets() { + return recordSets; + } + + @Override + public int hashCode() { + return Objects.hashCode(serviceName, name, countries, recordSets); + } + + /** + * permits equals comparisons with subtypes + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || !(obj instanceof GeoRegionGroup)) + return false; + GeoRegionGroup that = GeoRegionGroup.class.cast(obj); + return equal(this.serviceName, that.serviceName) && equal(this.name, that.name) + && equal(this.countries, that.countries) && equal(this.recordSets, that.recordSets); + } + + @Override + public String toString() { + return toStringHelper(this).add("serviceName", serviceName.orNull()).add("name", name) + .add("countries", countries).add("recordSets", recordSets).toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().from(this); + } + + public static class Builder { + + private Optional serviceName = Optional.absent(); + private String name; + private ImmutableList.Builder countries = ImmutableList.builder(); + private ImmutableList.Builder recordSets = ImmutableList.builder(); + + /** + * @see GeoRegionGroup#getServiceName() + */ + public Builder serviceName(String serviceName) { + this.serviceName = Optional.fromNullable(serviceName); + return this; + } + + /** + * @see GeoRegionGroup#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see GeoRegionGroup#getCountries() + */ + public Builder addCountry(String country) { + this.countries.add(country); + return this; + } + + /** + * replaces current record sets + * + * @see GeoRegionGroup#getCountries() + */ + public Builder countries(Iterable countries) { + this.countries = ImmutableList. builder().addAll(countries); + return this; + } + + /** + * @see GeoRegionGroup#getCountries() + */ + public Builder addAllCountries(Iterable countries) { + this.countries.addAll(countries); + return this; + } + + /** + * @see GeoRegionGroup#getRecordSets() + */ + public Builder addRecordSet(RecordSet recordSet) { + this.recordSets.add(recordSet); + return this; + } + + /** + * replaces current record sets + * + * @see GeoRegionGroup#getRecordSets() + */ + public Builder recordSets(Iterable recordSets) { + this.recordSets = ImmutableList. builder().addAll(recordSets); + return this; + } + + /** + * @see GeoRegionGroup#getRecordSets() + */ + public Builder addAllRecordSets(Iterable recordSets) { + this.recordSets.addAll(recordSets); + return this; + } + + public GeoRegionGroup build() { + return new GeoRegionGroup(serviceName, name, countries.build(), recordSets.build()); + } + + public Builder from(GeoRegionGroup in) { + return serviceName(in.serviceName.orNull()).name(in.name).countries(in.countries).recordSets(in.recordSets); + } + } +} diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/GeoService.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/GeoService.java new file mode 100644 index 0000000000..95d7797688 --- /dev/null +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/GeoService.java @@ -0,0 +1,195 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, String 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; + +/** + * @author Adrian Cole + */ +public class GeoService { + + private final String name; + private final boolean active; + private final int ttl; + private final List nodes; + private final List groups; + + private GeoService(String name, boolean active, int ttl, List nodes, List groups) { + this.name = checkNotNull(name, "name"); + this.active = checkNotNull(active, "active"); + this.ttl = checkNotNull(ttl, "ttl"); + this.nodes = checkNotNull(nodes, "nodes of %s", name); + this.groups = checkNotNull(groups, "groups of %s", name); + } + + public String getName() { + return name; + } + + public boolean isActive() { + return active; + } + + public int getTTL() { + return ttl; + } + + public List getNodes() { + return nodes; + } + + public List getGroups() { + return groups; + } + + @Override + public int hashCode() { + return Objects.hashCode(active, name, nodes, groups); + } + + /** + * permits equals comparisons with subtypes + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || !(obj instanceof GeoService)) + return false; + GeoService that = GeoService.class.cast(obj); + return equal(this.active, that.active) && equal(this.name, that.name) && equal(this.ttl, that.ttl) + && equal(this.nodes, that.nodes) && equal(this.groups, that.groups); + } + + @Override + public String toString() { + return toStringHelper(this).add("active", active).add("name", name).add("ttl", ttl).add("nodes", nodes).add("groups", groups) + .toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().from(this); + } + + public static class Builder { + + private String name; + private boolean active; + protected int ttl = -1; + private ImmutableList.Builder nodes = ImmutableList.builder(); + private ImmutableList.Builder groups = ImmutableList.builder(); + + /** + * @see GeoService#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see GeoService#isActive() + */ + public Builder active(boolean active) { + this.active = active; + return this; + } + + /** + * @see Builder#getTTL() + */ + public Builder ttl(int ttl) { + this.ttl = ttl; + return this; + } + + /** + * @see GeoService#getNodes() + */ + public Builder addNode(Node node) { + this.nodes.add(node); + return this; + } + + /** + * replaces current region groups + * + * @see GeoService#getNodes() + */ + public Builder nodes(Iterable nodes) { + this.nodes = ImmutableList. builder().addAll(nodes); + return this; + } + + /** + * @see GeoService#getNodes() + */ + public Builder addAllNodes(Iterable nodes) { + this.nodes.addAll(nodes); + return this; + } + + /** + * @see GeoService#getGroups() + */ + public Builder addGroup(GeoRegionGroup group) { + this.groups.add(group); + return this; + } + + /** + * replaces current region groups + * + * @see GeoService#getGroups() + */ + public Builder groups(Iterable groups) { + this.groups = ImmutableList. builder().addAll(groups); + return this; + } + + /** + * @see GeoService#getGroups() + */ + public Builder addAllGroups(Iterable groups) { + this.groups.addAll(groups); + return this; + } + + public GeoService build() { + return new GeoService(name, active, ttl, nodes.build(), groups.build()); + } + + public Builder from(GeoService in) { + return name(in.name).active(in.active).ttl(in.ttl).nodes(in.nodes).groups(in.groups); + } + } + +} diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/Node.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/Node.java new file mode 100644 index 0000000000..ab8882fd2b --- /dev/null +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/Node.java @@ -0,0 +1,77 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, String 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.domain; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.beans.ConstructorProperties; + +import com.google.common.base.Objects; + +public class Node { + + public static Node create(String fqdn, String zone) { + return new Node(fqdn, zone); + } + + private final String fqdn; + private final String zone; + + @ConstructorProperties({ "fqdn", "zone" }) + protected Node(String fqdn, String zone) { + this.fqdn = checkNotNull(fqdn, "fqdn"); + this.zone = checkNotNull(zone, "zone for %s", fqdn); + } + + /** + * Fully qualified domain name of a node in the zone + */ + public String getFQDN() { + return fqdn; + } + + /** + * Name of the zone + */ + public String getZone() { + return zone; + } + + @Override + public int hashCode() { + return Objects.hashCode(fqdn, zone); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Node that = Node.class.cast(obj); + return Objects.equal(this.fqdn, that.fqdn) && Objects.equal(this.zone, that.zone); + } + + @Override + public String toString() { + return Objects.toStringHelper("").add("fqdn", fqdn).add("zone", zone).toString(); + } +} diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/RecordId.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/RecordId.java index 2f54f99040..e80aa72ca9 100644 --- a/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/RecordId.java +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/RecordId.java @@ -30,35 +30,18 @@ import com.google.common.base.Objects.ToStringHelper; /** * @author Adrian Cole */ -public class RecordId { +public class RecordId extends Node { private final long id; - private final String zone; - private final String fqdn; private final String type; - @ConstructorProperties({ "zone", "fqdn", "record_type", "record_id" }) - RecordId(String zone, String fqdn, String type, long id) { + @ConstructorProperties({"fqdn", "zone", "record_type", "record_id" }) + RecordId(String fqdn, String zone, String type, long id) { + super(fqdn, zone); this.id = checkNotNull(id, "id"); - this.fqdn = checkNotNull(fqdn, "fqdn of %s", id); - this.zone = checkNotNull(zone, "zone of %s", id); this.type = checkNotNull(type, "type of %s", id); } - /** - * Name of the zone - */ - public String getZone() { - return zone; - } - - /** - * Fully qualified domain name of a node in the zone - */ - public String getFQDN() { - return fqdn; - } - /** * The RRType of the record */ @@ -75,7 +58,7 @@ public class RecordId { @Override public int hashCode() { - return Objects.hashCode(zone, fqdn, type, id); + return Objects.hashCode(getZone(), getFQDN(), type, id); } /** @@ -88,8 +71,7 @@ public class RecordId { if (obj == null || !(obj instanceof RecordId)) return false; RecordId that = RecordId.class.cast(obj); - return equal(this.zone, that.zone) && equal(this.fqdn, that.fqdn) && equal(this.type, that.type) - && equal(this.id, that.id); + return super.equals(obj) && equal(this.type, that.type) && equal(this.id, that.id); } @Override @@ -98,7 +80,7 @@ public class RecordId { } protected ToStringHelper string() { - return toStringHelper(this).add("zone", zone).add("fqdn", fqdn).add("type", type).add("id", id); + return toStringHelper(this).add("fqdn", getFQDN()).add("zone", getZone()).add("type", type).add("id", id); } public static Builder recordIdBuilder() { @@ -112,24 +94,24 @@ public class RecordId { public abstract static class Builder> { protected abstract B self(); - protected String zone; protected String fqdn; + protected String zone; protected String type; protected long id; /** - * @see RecordId#getZone() + * @see Node#getFQDN() */ - public B zone(String zone) { - this.zone = zone; + public B fqdn(String fqdn) { + this.fqdn = fqdn; return self(); } /** - * @see RecordId#getFQDN() + * @see Node#getZone() */ - public B fqdn(String fqdn) { - this.fqdn = fqdn; + public B zone(String zone) { + this.zone = zone; return self(); } @@ -150,11 +132,11 @@ public class RecordId { } public RecordId build() { - return new RecordId(zone, fqdn, type, id); + return new RecordId(fqdn, zone, type, id); } public B from(RecordId in) { - return zone(in.zone).fqdn(in.fqdn).type(in.type).id(in.id); + return fqdn(in.getFQDN()).zone(in.getZone()).type(in.type).id(in.id); } } diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/RecordSet.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/RecordSet.java new file mode 100644 index 0000000000..3e7ab7f149 --- /dev/null +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/domain/RecordSet.java @@ -0,0 +1,238 @@ +package org.jclouds.dynect.v3.domain; + +import static com.google.common.base.Objects.equal; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Map; + +import org.jclouds.dynect.v3.domain.RecordSet.Value; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; +import com.google.common.collect.ForwardingList; +import com.google.common.collect.ImmutableList; + +/** + * A set of records which shared the same name, type, and ttl + * + * @author Adrian Cole + */ +public class RecordSet extends ForwardingList { + + private final String type; + private final int ttl; + private transient final List values; + + private RecordSet(String type, int ttl, List values) { + this.type = checkNotNull(type, "type"); + this.ttl = ttl; + checkArgument(ttl >= 0, "ttl must be >=0"); + this.values = checkNotNull(values, "values"); + } + + /** + * @see Record#getType() + */ + public String getType() { + return type; + } + + /** + * @see Record#getTTL() + */ + public int getTTL() { + return ttl; + } + + public static class Value { + private final Optional label; + private final Optional weight; + private final Map rdata; + + private Value(Optional label, Optional weight, Map rdata) { + this.label = checkNotNull(label, "label"); + this.weight = checkNotNull(weight, "weight"); + this.rdata = checkNotNull(rdata, "rdata"); + } + + /** + * The label of the value. + */ + public Optional getLabel() { + return label; + } + + /** + * The relative weight of the value. + */ + public Optional getWeight() { + return weight; + } + + /** + * @see Record#getRData() + */ + public Map getRData() { + return rdata; + } + + @Override + public int hashCode() { + return Objects.hashCode(label, weight, rdata); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + Value that = Value.class.cast(obj); + return equal(this.label, that.label) && equal(this.weight, that.weight) && equal(this.rdata, that.rdata); + } + + @Override + public String toString() { + return toStringHelper("").omitNullValues().add("label", label.orNull()).add("weight", weight.orNull()) + .add("rdata", rdata).toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().from(this); + } + + public final static class Builder { + private Optional label = Optional.absent(); + private Optional weight = Optional.absent(); + private Map rdata; + + /** + * @see Value#getLabel() + */ + public Builder label(String label) { + this.label = Optional.fromNullable(label); + return this; + } + + /** + * @see Value#getWeight() + */ + public Builder weight(Integer weight) { + this.weight = Optional.fromNullable(weight); + return this; + } + + /** + * @see Record#getRData() + */ + public Builder rdata(Map rdata) { + this.rdata = rdata; + return this; + } + + public Value build() { + return new Value(label, weight, rdata); + } + + public Builder from(Value in) { + return label(in.label.orNull()).weight(in.weight.orNull()).rdata(in.rdata); + } + } + } + + @Override + public int hashCode() { + return Objects.hashCode(type, ttl, values); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null || getClass() != obj.getClass()) + return false; + RecordSet that = RecordSet.class.cast(obj); + return equal(this.type, that.type) && equal(this.ttl, that.ttl) && equal(this.values, that.values); + } + + @Override + public String toString() { + return toStringHelper("").omitNullValues().add("type", type).add("ttl", ttl).add("values", values).toString(); + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().from(this); + } + + public final static class Builder { + private String type; + private int ttl = -1; + private ImmutableList.Builder values = ImmutableList.builder(); + + /** + * @see RecordSet#getType() + */ + public Builder type(String type) { + this.type = type; + return this; + } + + /** + * @see RecordSet#getTTL() + */ + public Builder ttl(int ttl) { + this.ttl = ttl; + return this; + } + + /** + * @see RecordSet#iterator() + */ + public Builder add(Value value) { + this.values.add(value); + return this; + } + + /** + * replaces current values + * + * @see RecordSet#iterator() + */ + public Builder values(Iterable values) { + this.values = ImmutableList. builder().addAll(values); + return this; + } + + /** + * @see RecordSet#iterator() + */ + public Builder addAll(Iterable values) { + this.values.addAll(values); + return this; + } + + public RecordSet build() { + return new RecordSet(type, ttl, values.build()); + } + + public Builder from(RecordSet in) { + return type(in.type).ttl(in.ttl).values(in.values); + } + } + + @Override + protected List delegate() { + return values; + } +} diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/GeoRegionGroupApi.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/GeoRegionGroupApi.java new file mode 100644 index 0000000000..61f8c5dff6 --- /dev/null +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/GeoRegionGroupApi.java @@ -0,0 +1,80 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.features; + +import javax.inject.Named; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.dynect.v3.DynECTExceptions.JobStillRunningException; +import org.jclouds.dynect.v3.domain.GeoRegionGroup; +import org.jclouds.dynect.v3.filters.AlwaysAddContentType; +import org.jclouds.dynect.v3.filters.SessionManager; +import org.jclouds.dynect.v3.functions.ExtractLastPathComponent; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.Headers; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.Transform; + +import com.google.common.collect.FluentIterable; + +/** + * @see + * @author Adrian Cole + */ +@Headers(keys = "API-Version", values = "{jclouds.api-version}") +@Path("/GeoRegionGroup/{serviceName}") +@RequestFilters({ AlwaysAddContentType.class, SessionManager.class }) +public interface GeoRegionGroupApi { + /** + * Lists all geo region group names. + * + * @throws JobStillRunningException + * if a different job in the session is still running + */ + @Named("ListGeoRegionGroupNames") + @GET + @SelectJson("data") + @Transform(ExtractLastPathComponent.class) + FluentIterable list() throws JobStillRunningException; + + /** + * Retrieves information about the specified geo region group + * + * @param groupName + * name of the group to get information about. ex + * {@code api-prod} + * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running + */ + @Named("GetGeoRegionGroup") + @GET + @Path("/{groupName}") + @SelectJson("data") + @Fallback(NullOnNotFoundOr404.class) + @Nullable + GeoRegionGroup get(@PathParam("groupName") String groupName) throws JobStillRunningException; +} diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/GeoServiceApi.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/GeoServiceApi.java new file mode 100644 index 0000000000..757f54832b --- /dev/null +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/GeoServiceApi.java @@ -0,0 +1,80 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.features; + +import javax.inject.Named; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import org.jclouds.Fallbacks.NullOnNotFoundOr404; +import org.jclouds.dynect.v3.DynECTExceptions.JobStillRunningException; +import org.jclouds.dynect.v3.domain.GeoService; +import org.jclouds.dynect.v3.filters.AlwaysAddContentType; +import org.jclouds.dynect.v3.filters.SessionManager; +import org.jclouds.dynect.v3.functions.ExtractLastPathComponent; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.Headers; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; +import org.jclouds.rest.annotations.Transform; + +import com.google.common.collect.FluentIterable; + +/** + * @see + * @author Adrian Cole + */ +@Headers(keys = "API-Version", values = "{jclouds.api-version}") +@Path("/Geo") +@RequestFilters({ AlwaysAddContentType.class, SessionManager.class }) +public interface GeoServiceApi { + /** + * Lists all geo service names. + * + * @throws JobStillRunningException + * if a different job in the session is still running + */ + @Named("ListGeoServiceNames") + @GET + @SelectJson("data") + @Transform(ExtractLastPathComponent.class) + FluentIterable list() throws JobStillRunningException; + + /** + * Retrieves information about the specified geo service. + * + * @param serviceName + * name of the service to get information about. ex + * {@code api-prod} + * @return null if not found + * @throws JobStillRunningException + * if a different job in the session is still running + */ + @Named("GetGeoService") + @GET + @Path("/{serviceName}") + @SelectJson("data") + @Fallback(NullOnNotFoundOr404.class) + @Nullable + GeoService get(@PathParam("serviceName") String serviceName) throws JobStillRunningException; +} diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java index 5e6d6a20e5..2887d8d7a3 100644 --- a/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/features/ZoneApi.java @@ -40,7 +40,7 @@ import org.jclouds.dynect.v3.domain.Zone; import org.jclouds.dynect.v3.domain.Zone.SerialStyle; import org.jclouds.dynect.v3.filters.AlwaysAddContentType; import org.jclouds.dynect.v3.filters.SessionManager; -import org.jclouds.dynect.v3.functions.ExtractZoneNames; +import org.jclouds.dynect.v3.functions.ExtractLastPathComponent; import org.jclouds.javax.annotation.Nullable; import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.rest.annotations.BinderParam; @@ -72,7 +72,7 @@ public interface ZoneApi { @GET @Path("/Zone") @SelectJson("data") - @Transform(ExtractZoneNames.class) + @Transform(ExtractLastPathComponent.class) FluentIterable list() throws JobStillRunningException; /** diff --git a/providers/dynect/src/main/java/org/jclouds/dynect/v3/functions/ExtractZoneNames.java b/providers/dynect/src/main/java/org/jclouds/dynect/v3/functions/ExtractLastPathComponent.java similarity index 65% rename from providers/dynect/src/main/java/org/jclouds/dynect/v3/functions/ExtractZoneNames.java rename to providers/dynect/src/main/java/org/jclouds/dynect/v3/functions/ExtractLastPathComponent.java index 8b6da2cd20..e9794868d7 100644 --- a/providers/dynect/src/main/java/org/jclouds/dynect/v3/functions/ExtractZoneNames.java +++ b/providers/dynect/src/main/java/org/jclouds/dynect/v3/functions/ExtractLastPathComponent.java @@ -18,28 +18,34 @@ */ package org.jclouds.dynect.v3.functions; +import static com.google.common.base.Preconditions.checkState; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import com.google.common.base.Function; import com.google.common.collect.FluentIterable; /** - * Zones come back encoded in REST paths, such as - * {@code /REST/Zone/jclouds.org/} + * Zones, Geo Services, and Geo region groups come back encoded in REST paths, such as + * {@code /REST/Geo/srv-global/} * * @author Adrian Cole * */ -public final class ExtractZoneNames implements Function, FluentIterable> { +public final class ExtractLastPathComponent implements Function, FluentIterable> { public FluentIterable apply(FluentIterable in) { return in.transform(ExtractNameInPath.INSTANCE); } static enum ExtractNameInPath implements Function { INSTANCE; - - final int position = "/REST/Zone/".length(); + public static final Pattern DEFAULT_PATTERN = Pattern.compile("/REST.*/([^/]+)/?$"); public String apply(String in) { - return in.substring(position, in.length() - 1); + Matcher matcher = DEFAULT_PATTERN.matcher(in); + checkState(matcher.find() && matcher.groupCount() == 1, "%s didn't match %s", in, DEFAULT_PATTERN); + return matcher.group(1); } } } diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoRegionGroupApiExpectTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoRegionGroupApiExpectTest.java new file mode 100644 index 0000000000..cf9b639644 --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoRegionGroupApiExpectTest.java @@ -0,0 +1,67 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, String 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.features; + +import static com.google.common.net.HttpHeaders.CONTENT_TYPE; +import static javax.ws.rs.HttpMethod.GET; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static javax.ws.rs.core.Response.Status.OK; +import static org.testng.Assert.assertEquals; + +import org.jclouds.dynect.v3.DynECTApi; +import org.jclouds.dynect.v3.internal.BaseDynECTApiExpectTest; +import org.jclouds.dynect.v3.parse.ListGeoRegionGroupsResponseTest; +import org.jclouds.dynect.v3.parse.GetGeoRegionGroupResponseTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "GeoRegionGroupApiExpectTest") +public class GeoRegionGroupApiExpectTest extends BaseDynECTApiExpectTest { + + HttpRequest list = HttpRequest.builder().method(GET).endpoint("https://api2.dynect.net/REST/GeoRegionGroup/srv") + .addHeader("API-Version", "3.3.8").addHeader(CONTENT_TYPE, APPLICATION_JSON) + .addHeader("Auth-Token", authToken).build(); + + HttpResponse listResponse = HttpResponse.builder().statusCode(OK.getStatusCode()) + .payload(payloadFromResourceWithContentType("/list_geo_regiongroups.json", APPLICATION_JSON)).build(); + + public void testListWhenResponseIs2xx() { + DynECTApi success = requestsSendResponses(createSession, createSessionResponse, list, listResponse); + assertEquals(success.getGeoRegionGroupApiForService("srv").list().toString(), + new ListGeoRegionGroupsResponseTest().expected().toString()); + } + + HttpRequest get = HttpRequest.builder().method(GET) + .endpoint("https://api2.dynect.net/REST/GeoRegionGroup/srv/Everywhere%20Else") + .addHeader("API-Version", "3.3.8").addHeader(CONTENT_TYPE, APPLICATION_JSON) + .addHeader("Auth-Token", authToken).build(); + + HttpResponse getResponse = HttpResponse.builder().statusCode(OK.getStatusCode()) + .payload(payloadFromResourceWithContentType("/get_geo_regiongroup.json", APPLICATION_JSON)).build(); + + public void testGetWhenResponseIs2xx() { + DynECTApi success = requestsSendResponses(createSession, createSessionResponse, get, getResponse); + assertEquals(success.getGeoRegionGroupApiForService("srv").get("Everywhere Else").toString(), + new GetGeoRegionGroupResponseTest().expected().toString()); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoRegionGroupApiLiveTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoRegionGroupApiLiveTest.java new file mode 100644 index 0000000000..9b5e5b2023 --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoRegionGroupApiLiveTest.java @@ -0,0 +1,81 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, String 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.features; + +import static java.util.logging.Logger.getAnonymousLogger; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.dynect.v3.domain.RecordSet; +import org.jclouds.dynect.v3.domain.RecordSet.Value; +import org.jclouds.dynect.v3.domain.GeoRegionGroup; +import org.jclouds.dynect.v3.internal.BaseDynECTApiLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +/** + * @author Adrian Cole + */ +@Test(groups = "live", singleThreaded = true, testName = "GeoRegionGroupApiLiveTest") +public class GeoRegionGroupApiLiveTest extends BaseDynECTApiLiveTest { + + @Test + protected void testListAndGetGeoRegionGroups() { + for (String service : geoApi().list()) { + GeoRegionGroupApi api = api(service); + ImmutableList groups = api.list().toList(); + getAnonymousLogger().info("geo service: " + service + " group count: " + groups.size()); + for (String group : groups) { + GeoRegionGroup groupDetail = api.get(group); + assertNotNull(groupDetail.getServiceName().get(), "ServiceName cannot be null " + groupDetail); + checkGeoRegionGroup(groupDetail); + } + } + } + + static void checkGeoRegionGroup(GeoRegionGroup group) { + assertNotNull(group.getName(), "Name cannot be null " + group); + assertTrue(group.getCountries().size() > 0, "countries must be assigned " + group); + assertTrue(group.getRecordSets().size() > 0, "RecordSets must be assigned " + group); + for (RecordSet recordSet : group.getRecordSets()) + checkRecordSet(recordSet); + } + + static void checkRecordSet(RecordSet rset) { + assertNotNull(rset.getType(), "Type cannot be null " + rset); + assertTrue(rset.getTTL() >= 0, "TTL cannot be negative " + rset); + for (Value value : rset) + checkValue(value); + } + + static void checkValue(Value value) { + assertNotNull(value.getLabel(), "Label cannot be null " + value); + assertNotNull(value.getWeight(), "Weight cannot be null " + value); + assertTrue(value.getRData().size() > 0, "RData entries should be present: " + value); + } + + protected GeoRegionGroupApi api(String serviceName) { + return api.getGeoRegionGroupApiForService(serviceName); + } + + protected GeoServiceApi geoApi() { + return api.getGeoServiceApi(); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoServiceApiExpectTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoServiceApiExpectTest.java new file mode 100644 index 0000000000..97f9b50d8d --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoServiceApiExpectTest.java @@ -0,0 +1,66 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, String 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.features; + +import static com.google.common.net.HttpHeaders.CONTENT_TYPE; +import static javax.ws.rs.HttpMethod.GET; +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; +import static javax.ws.rs.core.Response.Status.OK; +import static org.testng.Assert.assertEquals; + +import org.jclouds.dynect.v3.DynECTApi; +import org.jclouds.dynect.v3.internal.BaseDynECTApiExpectTest; +import org.jclouds.dynect.v3.parse.GetGeoServiceResponseTest; +import org.jclouds.dynect.v3.parse.ListGeoServicesResponseTest; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.testng.annotations.Test; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit", testName = "GeoServiceApiExpectTest") +public class GeoServiceApiExpectTest extends BaseDynECTApiExpectTest { + + HttpRequest list = HttpRequest.builder().method(GET).endpoint("https://api2.dynect.net/REST/Geo") + .addHeader("API-Version", "3.3.8").addHeader(CONTENT_TYPE, APPLICATION_JSON) + .addHeader("Auth-Token", authToken).build(); + + HttpResponse listResponse = HttpResponse.builder().statusCode(OK.getStatusCode()) + .payload(payloadFromResourceWithContentType("/list_geo_services.json", APPLICATION_JSON)).build(); + + public void testListWhenResponseIs2xx() { + DynECTApi success = requestsSendResponses(createSession, createSessionResponse, list, listResponse); + assertEquals(success.getGeoServiceApi().list().toString(), new ListGeoServicesResponseTest().expected() + .toString()); + } + + HttpRequest get = HttpRequest.builder().method(GET).endpoint("https://api2.dynect.net/REST/Geo/srv") + .addHeader("API-Version", "3.3.8").addHeader(CONTENT_TYPE, APPLICATION_JSON) + .addHeader("Auth-Token", authToken).build(); + + HttpResponse getResponse = HttpResponse.builder().statusCode(OK.getStatusCode()) + .payload(payloadFromResourceWithContentType("/get_geo_service.json", APPLICATION_JSON)).build(); + + public void testGetWhenResponseIs2xx() { + DynECTApi success = requestsSendResponses(createSession, createSessionResponse, get, getResponse); + assertEquals(success.getGeoServiceApi().get("srv").toString(), new GetGeoServiceResponseTest().expected() + .toString()); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoServiceApiLiveTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoServiceApiLiveTest.java new file mode 100644 index 0000000000..244d0c69a7 --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/features/GeoServiceApiLiveTest.java @@ -0,0 +1,60 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, String 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.dynect.v3.features; + +import static java.util.logging.Logger.getAnonymousLogger; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import org.jclouds.dynect.v3.domain.GeoService; +import org.jclouds.dynect.v3.domain.GeoRegionGroup; +import org.jclouds.dynect.v3.internal.BaseDynECTApiLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; + +/** + * @author Adrian Cole + */ +@Test(groups = "live", singleThreaded = true, testName = "GeoServiceApiLiveTest") +public class GeoServiceApiLiveTest extends BaseDynECTApiLiveTest { + + @Test + protected void testListAndGetGeoServices() { + ImmutableList geos = api().list().toList(); + getAnonymousLogger().info("geo services: " + geos.size()); + for (String fqdn : geos) { + GeoService geo = api().get(fqdn); + checkGeoService(geo); + } + } + + static void checkGeoService(GeoService service) { + assertNotNull(service.getName(), "Name cannot be null " + service); + assertTrue(service.getTTL() >= 0, "TTL cannot be negative " + service); + assertTrue(service.getNodes().size() > 0, "Nodes must be assigned " + service); + assertTrue(service.getGroups().size() > 0, "Groups must be assigned " + service); + for (GeoRegionGroup group : service.getGroups()) + GeoRegionGroupApiLiveTest.checkGeoRegionGroup(group); + } + + protected GeoServiceApi api() { + return api.getGeoServiceApi(); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/functions/ExtractZoneNamesTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/functions/ExtractLastPathComponentTest.java similarity index 85% rename from providers/dynect/src/test/java/org/jclouds/dynect/v3/functions/ExtractZoneNamesTest.java rename to providers/dynect/src/test/java/org/jclouds/dynect/v3/functions/ExtractLastPathComponentTest.java index f21681b435..806d42fcb6 100644 --- a/providers/dynect/src/test/java/org/jclouds/dynect/v3/functions/ExtractZoneNamesTest.java +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/functions/ExtractLastPathComponentTest.java @@ -21,7 +21,7 @@ package org.jclouds.dynect.v3.functions; import static org.testng.Assert.assertEquals; -import org.jclouds.dynect.v3.functions.ExtractZoneNames.ExtractNameInPath; +import org.jclouds.dynect.v3.functions.ExtractLastPathComponent.ExtractNameInPath; import org.testng.annotations.Test; import com.google.common.collect.FluentIterable; @@ -31,14 +31,14 @@ import com.google.common.collect.ImmutableSet; * @author Adrian Cole */ @Test(groups = "unit") -public class ExtractZoneNamesTest { - ExtractZoneNames fn = new ExtractZoneNames(); +public class ExtractLastPathComponentTest { + ExtractLastPathComponent fn = new ExtractLastPathComponent(); public void testExtractNameInPath() { assertEquals(ExtractNameInPath.INSTANCE.apply("/REST/Zone/jclouds.org/"), "jclouds.org"); } - public void testExtractZoneNames() { + public void testExtractLastPathComponent() { assertEquals(fn.apply(FluentIterable.from(ImmutableSet.of("/REST/Zone/jclouds.org/"))).toSet(), ImmutableSet.of("jclouds.org")); } diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetGeoRegionGroupResponseTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetGeoRegionGroupResponseTest.java new file mode 100644 index 0000000000..2dce333f0a --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetGeoRegionGroupResponseTest.java @@ -0,0 +1,67 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.jclouds.dynect.v3.parse; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.dynect.v3.domain.RecordSet; +import org.jclouds.dynect.v3.domain.RecordSet.Value; +import org.jclouds.dynect.v3.domain.GeoRegionGroup; +import org.jclouds.dynect.v3.internal.BaseDynECTParseTest; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit") +public class GetGeoRegionGroupResponseTest extends BaseDynECTParseTest { + + @Override + public String resource() { + return "/get_geo_regiongroup.json"; + } + + @Override + @SelectJson("data") + @Consumes(MediaType.APPLICATION_JSON) + public GeoRegionGroup expected() { + return GeoRegionGroup + .builder() + .name("Everywhere Else") + .countries(ImmutableList.of("11", "16", "12", "17", "15", "14")) + .serviceName("CCS") + .addRecordSet( + RecordSet + .builder() + .ttl(0) + .type("CNAME") + .add(Value + .builder() + .rdata( + ImmutableMap. builder() + .put("cname", "srv-938089264.us-east-1.elb.amazonaws.com.").build()).build()) + .build()).build(); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetGeoServiceResponseTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetGeoServiceResponseTest.java new file mode 100644 index 0000000000..ff3813b528 --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/GetGeoServiceResponseTest.java @@ -0,0 +1,107 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.jclouds.dynect.v3.parse; + +import javax.ws.rs.Consumes; +import javax.ws.rs.core.MediaType; + +import org.jclouds.dynect.v3.domain.GeoService; +import org.jclouds.dynect.v3.domain.Node; +import org.jclouds.dynect.v3.domain.RecordSet; +import org.jclouds.dynect.v3.domain.GeoRegionGroup; +import org.jclouds.dynect.v3.domain.RecordSet.Value; +import org.jclouds.dynect.v3.internal.BaseDynECTParseTest; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit") +public class GetGeoServiceResponseTest extends BaseDynECTParseTest { + + @Override + public String resource() { + return "/get_geo_service.json"; + } + + @Override + @SelectJson("data") + @Consumes(MediaType.APPLICATION_JSON) + public GeoService expected() { + return GeoService + .builder() + .name("CCS") + .active(true) + .ttl(30) + .addNode(Node.create("srv.jclouds.org", "jclouds.org")) + .addGroup( + GeoRegionGroup + .builder() + .name("Everywhere Else") + .countries(ImmutableList.of("11", "16", "12", "17", "15", "14")) + .addRecordSet( + RecordSet + .builder() + .ttl(0) + .type("CNAME") + .add(Value + .builder() + .rdata( + ImmutableMap. builder() + .put("cname", "srv-000000001.us-east-1.elb.amazonaws.com.") + .build()).build()).build()).build()) + .addGroup( + GeoRegionGroup + .builder() + .name("Europe") + .countries(ImmutableList.of("13")) + .addRecordSet( + RecordSet + .builder() + .ttl(0) + .type("CNAME") + .add(Value + .builder() + .rdata( + ImmutableMap. builder() + .put("cname", "srv-000000001.eu-west-1.elb.amazonaws.com.") + .build()).build()).build()).build()) + .addGroup( + GeoRegionGroup + .builder() + .name("Fallback") + .countries(ImmutableList.of("@!", "@@")) + .addRecordSet( + RecordSet + .builder() + .ttl(0) + .type("CNAME") + .add(Value + .builder() + .rdata( + ImmutableMap. builder() + .put("cname", "srv-000000002.us-east-1.elb.amazonaws.com.") + .build()).build()).build()).build()).build(); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListGeoRegionGroupsResponseTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListGeoRegionGroupsResponseTest.java new file mode 100644 index 0000000000..d68be9bc91 --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListGeoRegionGroupsResponseTest.java @@ -0,0 +1,58 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.jclouds.dynect.v3.parse; + +import static com.google.common.base.Functions.compose; + +import org.jclouds.dynect.v3.functions.ExtractLastPathComponent; +import org.jclouds.dynect.v3.internal.BaseDynECTParseTest; +import org.jclouds.http.HttpResponse; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Injector; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit") +public class ListGeoRegionGroupsResponseTest extends BaseDynECTParseTest> { + + @Override + public String resource() { + return "/list_geo_regiongroups.json"; + } + + @Override + @SelectJson("data") + public FluentIterable expected() { + return FluentIterable.from(ImmutableSet.of("Everywhere Else", "Europe", "Fallback")); + } + + // TODO: currently our parsing of annotations on expected() ignores + // @Transform + @Override + protected Function> parser(Injector i) { + return compose(new ExtractLastPathComponent(), super.parser(i)); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListGeoServicesResponseTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListGeoServicesResponseTest.java new file mode 100644 index 0000000000..60958edc17 --- /dev/null +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListGeoServicesResponseTest.java @@ -0,0 +1,58 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.jclouds.dynect.v3.parse; + +import static com.google.common.base.Functions.compose; + +import org.jclouds.dynect.v3.functions.ExtractLastPathComponent; +import org.jclouds.dynect.v3.internal.BaseDynECTParseTest; +import org.jclouds.http.HttpResponse; +import org.jclouds.rest.annotations.SelectJson; +import org.testng.annotations.Test; + +import com.google.common.base.Function; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Injector; + +/** + * @author Adrian Cole + */ +@Test(groups = "unit") +public class ListGeoServicesResponseTest extends BaseDynECTParseTest> { + + @Override + public String resource() { + return "/list_geo_services.json"; + } + + @Override + @SelectJson("data") + public FluentIterable expected() { + return FluentIterable.from(ImmutableSet.of("srv", "srv-log")); + } + + // TODO: currently our parsing of annotations on expected() ignores + // @Transform + @Override + protected Function> parser(Injector i) { + return compose(new ExtractLastPathComponent(), super.parser(i)); + } +} diff --git a/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListZonesResponseTest.java b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListZonesResponseTest.java index 3bb5bb219a..fdd6976cd3 100644 --- a/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListZonesResponseTest.java +++ b/providers/dynect/src/test/java/org/jclouds/dynect/v3/parse/ListZonesResponseTest.java @@ -21,7 +21,7 @@ package org.jclouds.dynect.v3.parse; import static com.google.common.base.Functions.compose; -import org.jclouds.dynect.v3.functions.ExtractZoneNames; +import org.jclouds.dynect.v3.functions.ExtractLastPathComponent; import org.jclouds.dynect.v3.internal.BaseDynECTParseTest; import org.jclouds.http.HttpResponse; import org.jclouds.rest.annotations.SelectJson; @@ -52,6 +52,6 @@ public class ListZonesResponseTest extends BaseDynECTParseTest> parser(Injector i) { - return compose(new ExtractZoneNames(), super.parser(i)); + return compose(new ExtractLastPathComponent(), super.parser(i)); } } diff --git a/providers/dynect/src/test/resources/get_geo_regiongroup.json b/providers/dynect/src/test/resources/get_geo_regiongroup.json new file mode 100644 index 0000000000..7c96df4384 --- /dev/null +++ b/providers/dynect/src/test/resources/get_geo_regiongroup.json @@ -0,0 +1,92 @@ +{ + "status": "success", + "data": { + "name": "Everywhere Else", + "weight": { + "aaaa_weight": [], + "a_weight": [], + "cname_weight": [] + }, + "countries": ["11", "16", "12", "17", "15", "14"], + "service_name": "CCS", + "rdata": { + "spf_rdata": [], + "px_rdata": [], + "srv_rdata": [], + "txt_rdata": [], + "soa_rdata": [], + "rp_rdata": [], + "ipseckey_rdata": [], + "dhcid_rdata": [], + "kx_rdata": [], + "key_rdata": [], + "aaaa_rdata": [], + "mx_rdata": [], + "dnskey_rdata": [], + "naptr_rdata": [], + "a_rdata": [], + "cname_rdata": [{ + "cname": "srv-938089264.us-east-1.elb.amazonaws.com." + } + ], + "cert_rdata": [], + "nsap_rdata": [], + "ptr_rdata": [], + "ds_rdata": [], + "sshfp_rdata": [], + "dname_rdata": [], + "ns_rdata": [], + "loc_rdata": [] + }, + "label": { + "a_label": [], + "key_label": [], + "ptr_label": [], + "srv_label": [], + "txt_label": [], + "spf_label": [], + "mx_label": [], + "rp_label": [], + "sshfp_label": [], + "dnskey_label": [], + "aaaa_label": [], + "dhcid_label": [], + "nsap_label": [], + "loc_label": [], + "px_label": [], + "cname_label": [], + "cert_label": [] + }, + "ttl": { + "dhcid_ttl": 0, + "key_ttl": 0, + "ptr_ttl": 0, + "srv_ttl": 0, + "mx_ttl": 0, + "aaaa_ttl": 0, + "rp_ttl": 0, + "loc_ttl": 0, + "dnskey_ttl": 0, + "cname_ttl": 0, + "cert_ttl": 0, + "nsap_ttl": 0, + "a_ttl": 0, + "px_ttl": 0, + "sshfp_ttl": 0, + "spf_ttl": 0, + "txt_ttl": 0 + }, + "serve_count": { + "a_serve_count": "", + "aaaa_serve_count": "" + } + }, + "job_id": 321503845, + "msgs": [{ + "INFO": "detail_region_groups: Here is your group", + "SOURCE": "BLL", + "ERR_CD": null, + "LVL": "INFO" + } + ] +} diff --git a/providers/dynect/src/test/resources/get_geo_service.json b/providers/dynect/src/test/resources/get_geo_service.json new file mode 100644 index 0000000000..b4a60e306f --- /dev/null +++ b/providers/dynect/src/test/resources/get_geo_service.json @@ -0,0 +1,260 @@ +{ + "status": "success", + "data": { + "active": "Y", + "nodes": [{ + "fqdn": "srv.jclouds.org", + "zone": "jclouds.org" + } + ], + "name": "CCS", + "groups": [{ + "name": "Everywhere Else", + "weight": { + "aaaa_weight": [], + "a_weight": [], + "cname_weight": [] + }, + "countries": ["11", "16", "12", "17", "15", "14"], + "rdata": { + "spf_rdata": [], + "px_rdata": [], + "srv_rdata": [], + "txt_rdata": [], + "soa_rdata": [], + "rp_rdata": [], + "ipseckey_rdata": [], + "dhcid_rdata": [], + "kx_rdata": [], + "key_rdata": [], + "aaaa_rdata": [], + "mx_rdata": [], + "dnskey_rdata": [], + "naptr_rdata": [], + "a_rdata": [], + "cname_rdata": [{ + "cname": "srv-000000001.us-east-1.elb.amazonaws.com." + } + ], + "cert_rdata": [], + "nsap_rdata": [], + "ptr_rdata": [], + "ds_rdata": [], + "sshfp_rdata": [], + "dname_rdata": [], + "ns_rdata": [], + "loc_rdata": [] + }, + "label": { + "a_label": [], + "key_label": [], + "ptr_label": [], + "srv_label": [], + "txt_label": [], + "spf_label": [], + "mx_label": [], + "rp_label": [], + "sshfp_label": [], + "dnskey_label": [], + "aaaa_label": [], + "dhcid_label": [], + "nsap_label": [], + "loc_label": [], + "px_label": [], + "cname_label": [], + "cert_label": [] + }, + "ttl": { + "dhcid_ttl": 0, + "key_ttl": 0, + "ptr_ttl": 0, + "srv_ttl": 0, + "mx_ttl": 0, + "aaaa_ttl": 0, + "rp_ttl": 0, + "loc_ttl": 0, + "dnskey_ttl": 0, + "cname_ttl": 0, + "cert_ttl": 0, + "nsap_ttl": 0, + "a_ttl": 0, + "px_ttl": 0, + "sshfp_ttl": 0, + "spf_ttl": 0, + "txt_ttl": 0 + }, + "serve_count": { + "a_serve_count": "", + "aaaa_serve_count": "" + } + }, { + "name": "Europe", + "weight": { + "aaaa_weight": [], + "a_weight": [], + "cname_weight": [] + }, + "countries": ["13"], + "rdata": { + "spf_rdata": [], + "px_rdata": [], + "srv_rdata": [], + "txt_rdata": [], + "soa_rdata": [], + "rp_rdata": [], + "ipseckey_rdata": [], + "dhcid_rdata": [], + "kx_rdata": [], + "key_rdata": [], + "aaaa_rdata": [], + "mx_rdata": [], + "dnskey_rdata": [], + "naptr_rdata": [], + "a_rdata": [], + "cname_rdata": [{ + "cname": "srv-000000001.eu-west-1.elb.amazonaws.com." + } + ], + "cert_rdata": [], + "nsap_rdata": [], + "ptr_rdata": [], + "ds_rdata": [], + "sshfp_rdata": [], + "dname_rdata": [], + "ns_rdata": [], + "loc_rdata": [] + }, + "label": { + "a_label": [], + "key_label": [], + "ptr_label": [], + "srv_label": [], + "txt_label": [], + "spf_label": [], + "mx_label": [], + "rp_label": [], + "sshfp_label": [], + "dnskey_label": [], + "aaaa_label": [], + "dhcid_label": [], + "nsap_label": [], + "loc_label": [], + "px_label": [], + "cname_label": [], + "cert_label": [] + }, + "ttl": { + "dhcid_ttl": 0, + "key_ttl": 0, + "ptr_ttl": 0, + "srv_ttl": 0, + "mx_ttl": 0, + "aaaa_ttl": 0, + "rp_ttl": 0, + "loc_ttl": 0, + "dnskey_ttl": 0, + "cname_ttl": 0, + "cert_ttl": 0, + "nsap_ttl": 0, + "a_ttl": 0, + "px_ttl": 0, + "sshfp_ttl": 0, + "spf_ttl": 0, + "txt_ttl": 0 + }, + "serve_count": { + "a_serve_count": "", + "aaaa_serve_count": "" + } + }, { + "name": "Fallback", + "weight": { + "aaaa_weight": [], + "a_weight": [], + "cname_weight": [] + }, + "countries": ["@!", "@@"], + "rdata": { + "spf_rdata": [], + "px_rdata": [], + "srv_rdata": [], + "txt_rdata": [], + "soa_rdata": [], + "rp_rdata": [], + "ipseckey_rdata": [], + "dhcid_rdata": [], + "kx_rdata": [], + "key_rdata": [], + "aaaa_rdata": [], + "mx_rdata": [], + "dnskey_rdata": [], + "naptr_rdata": [], + "a_rdata": [], + "cname_rdata": [{ + "cname": "srv-000000002.us-east-1.elb.amazonaws.com." + } + ], + "cert_rdata": [], + "nsap_rdata": [], + "ptr_rdata": [], + "ds_rdata": [], + "sshfp_rdata": [], + "dname_rdata": [], + "ns_rdata": [], + "loc_rdata": [] + }, + "label": { + "a_label": [], + "key_label": [], + "ptr_label": [], + "srv_label": [], + "txt_label": [], + "spf_label": [], + "mx_label": [], + "rp_label": [], + "sshfp_label": [], + "dnskey_label": [], + "aaaa_label": [], + "dhcid_label": [], + "nsap_label": [], + "loc_label": [], + "px_label": [], + "cname_label": [], + "cert_label": [] + }, + "ttl": { + "dhcid_ttl": 0, + "key_ttl": 0, + "ptr_ttl": 0, + "srv_ttl": 0, + "mx_ttl": 0, + "aaaa_ttl": 0, + "rp_ttl": 0, + "loc_ttl": 0, + "dnskey_ttl": 0, + "cname_ttl": 0, + "cert_ttl": 0, + "nsap_ttl": 0, + "a_ttl": 0, + "px_ttl": 0, + "sshfp_ttl": 0, + "spf_ttl": 0, + "txt_ttl": 0 + }, + "serve_count": { + "a_serve_count": "", + "aaaa_serve_count": "" + } + } + ], + "ttl": 30 + }, + "job_id": 321488519, + "msgs": [{ + "INFO": "detail: Here is your service", + "SOURCE": "BLL", + "ERR_CD": null, + "LVL": "INFO" + } + ] +} diff --git a/providers/dynect/src/test/resources/list_geo_regiongroups.json b/providers/dynect/src/test/resources/list_geo_regiongroups.json new file mode 100644 index 0000000000..dc45f5b326 --- /dev/null +++ b/providers/dynect/src/test/resources/list_geo_regiongroups.json @@ -0,0 +1,12 @@ +{ + "status": "success", + "data": ["/REST/GeoRegionGroup/srv/Everywhere Else", "/REST/GeoRegionGroup/srv/Europe", "/REST/GeoRegionGroup/srv/Fallback"], + "job_id": 321503402, + "msgs": [{ + "INFO": "get_region_groups: Here are your groups", + "SOURCE": "BLL", + "ERR_CD": null, + "LVL": "INFO" + } + ] +} diff --git a/providers/dynect/src/test/resources/list_geo_services.json b/providers/dynect/src/test/resources/list_geo_services.json new file mode 100644 index 0000000000..5e78d8a98a --- /dev/null +++ b/providers/dynect/src/test/resources/list_geo_services.json @@ -0,0 +1,12 @@ +{ + "status": "success", + "data": ["/REST/Geo/srv/", "/REST/Geo/srv-log/"], + "job_id": 321483166, + "msgs": [{ + "INFO": "GET: Found 2 services", + "SOURCE": "BLL", + "ERR_CD": null, + "LVL": "INFO" + } + ] +}