diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Address.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Address.java new file mode 100644 index 000000000000..b30293fb6d48 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Address.java @@ -0,0 +1,183 @@ +/* + * 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.gcloud.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.Objects; + +/** + * A Google Compute Engine address. With Compute Engine you can create static external IP addresses + * that are assigned to your project and persist until you explicitly release them. A region address + * can be assigned to a Compute Engine instance or to a regional forwarding rule. Compute Engine + * also allows you to create global addresses that are used for global forwarding rules. Both global + * addresses and global forwarding rules can only be used for HTTP load balancing. {@code Address} + * adds a layer of service-related functionality over {@link AddressInfo}. Objects of this class are + * immutable. To get an {@code Address} object with the most recent information use {@link #reload}. + * + * @see + * Static external IP addresses + * @see HTTP Load Balancing + */ +public class Address extends AddressInfo { + + private static final long serialVersionUID = 3457542817554062712L; + + private final ComputeOptions options; + private transient Compute compute; + + /** + * A builder for {@code Address} objects. + */ + public static class Builder extends AddressInfo.Builder { + + private final Compute compute; + private final AddressInfo.BuilderImpl infoBuilder; + + Builder(Compute compute, AddressId addressId) { + this.compute = compute; + this.infoBuilder = new AddressInfo.BuilderImpl(); + this.infoBuilder.addressId(addressId); + } + + Builder(Address address) { + this.compute = address.compute; + this.infoBuilder = new AddressInfo.BuilderImpl(address); + } + + @Override + public Builder address(String address) { + infoBuilder.address(address); + return this; + } + + @Override + Builder creationTimestamp(Long creationTimestamp) { + infoBuilder.creationTimestamp(creationTimestamp); + return this; + } + + @Override + public Builder description(String description) { + infoBuilder.description(description); + return this; + } + + @Override + Builder id(String id) { + infoBuilder.id(id); + return this; + } + + @Override + public Builder addressId(AddressId addressId) { + infoBuilder.addressId(addressId); + return this; + } + + @Override + Builder status(Status status) { + infoBuilder.status(status); + return this; + } + + @Override + Builder usage(Usage usage) { + infoBuilder.usage(usage); + return this; + } + + @Override + public Address build() { + return new Address(compute, infoBuilder); + } + } + + Address(Compute compute, AddressInfo.BuilderImpl infoBuilder) { + super(infoBuilder); + this.compute = checkNotNull(compute); + this.options = compute.options(); + } + + /** + * Checks if this address exists. + * + * @return {@code true} if this address exists, {@code false} otherwise + * @throws ComputeException upon failure + */ + public boolean exists() { + return reload(Compute.AddressOption.fields()) != null; + } + + /** + * Fetches the current address' latest information. Returns {@code null} if the address does not + * exist. + * + * @param options address options + * @return an {@code Address} object with latest information or {@code null} if not found + * @throws ComputeException upon failure + */ + public Address reload(Compute.AddressOption... options) { + return compute.get(addressId(), options); + } + + /** + * Deletes this address. + * + * @return an {@code Operation} object if delete request was successfully sent, {@code null} if + * the address was not found + * @throws ComputeException upon failure + */ + public Operation delete(Compute.OperationOption... options) { + return compute.delete(addressId(), options); + } + + /** + * Returns the address's {@code Compute} object used to issue requests. + */ + public Compute compute() { + return compute; + } + + @Override + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public final boolean equals(Object obj) { + return obj instanceof Address + && Objects.equals(toPb(), ((Address) obj).toPb()) + && Objects.equals(options, ((Address) obj).options); + } + + @Override + public final int hashCode() { + return Objects.hash(super.hashCode(), options); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + this.compute = options.service(); + } + + static Address fromPb(Compute compute, com.google.api.services.compute.model.Address addressPb) { + return new Address(compute, new AddressInfo.BuilderImpl(addressPb)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressId.java new file mode 100644 index 000000000000..c418ec2ae1ba --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressId.java @@ -0,0 +1,91 @@ +/* + * 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.gcloud.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Base class for Google Compute Engine address identities. + */ +public abstract class AddressId extends ResourceId { + + private static final long serialVersionUID = 147328216049936438L; + + private final String address; + + /** + * Possible types for a Google Compute Engine address identity. + */ + enum Type { + /** + * Global static external IP addresses can be assigned to global forwarding rules. + */ + GLOBAL, + + /** + * Region static external IP addresses can be assigned to instances and region forwarding rules. + */ + REGION + } + + AddressId(String project, String address) { + super(project); + this.address = checkNotNull(address); + } + + /** + * Returns the type of this address identity. + */ + public abstract Type type(); + + /** + * Returns the name of the address resource. The name must be 1-63 characters long and comply with + * RFC1035. Specifically, the name must match the regular expression + * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter, + * and all following characters must be a dash, lowercase letter, or digit, except the last + * character, which cannot be a dash. + * + * @see RFC1035 + */ + public String address() { + return address; + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("address", address); + } + + @Override + final int baseHashCode() { + return Objects.hash(super.baseHashCode(), address); + } + + @Override + final boolean baseEquals(ResourceId resourceId) { + return resourceId instanceof AddressId + && super.baseEquals(resourceId) + && Objects.equals(address, ((AddressId) resourceId).address); + } + + @Override + abstract AddressId setProjectId(String projectId); +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressInfo.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressInfo.java new file mode 100644 index 000000000000..249f8462d401 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/AddressInfo.java @@ -0,0 +1,572 @@ +/* + * 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.gcloud.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.api.services.compute.model.Address; +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +import org.joda.time.format.DateTimeFormatter; +import org.joda.time.format.ISODateTimeFormat; + +import java.io.Serializable; +import java.math.BigInteger; +import java.util.List; +import java.util.Objects; + +/** + * A Google Compute Engine address. With Compute Engine you can create static external IP addresses + * that are assigned to your project and persist until you explicitly release them. A region address + * can be assigned to a Compute Engine instance or to a regional forwarding rule. To create a region + * address, use a {@link RegionAddressId} identity. Compute Engine also allows you to create global + * addresses that are used for global forwarding rules. Both global addresses and global forwarding + * rules can only be used for HTTP load balancing. To create a global address, use a + * {@link GlobalAddressId} identity. + * + * @see + * Static external IP addresses + * @see HTTP Load Balancing + */ +public class AddressInfo implements Serializable { + + static final Function FROM_PB_FUNCTION = + new Function() { + @Override + public AddressInfo apply(Address pb) { + return AddressInfo.fromPb(pb); + } + }; + static final Function TO_PB_FUNCTION = + new Function() { + @Override + public Address apply(AddressInfo addressInfo) { + return addressInfo.toPb(); + } + }; + + private static final long serialVersionUID = 7678434703520207500L; + private static final DateTimeFormatter TIMESTAMP_FORMATTER = ISODateTimeFormat.dateTime(); + + private final String address; + private final Long creationTimestamp; + private final String description; + private final String id; + private final AddressId addressId; + private final Status status; + private final Usage usage; + + /** + * The status of the address. + */ + public enum Status { + + /** + * The address is reserved for the project and is available for use. + */ + RESERVED, + + /** + * The address is currently being used and thus not available. + */ + IN_USE + } + + /** + * Base class for a Google Compute Engine address's usage information. Implementations of this + * class represent different possible usages of a Compute Engine address. {@link InstanceUsage} + * contains information for region addresses assigned to a Google Compute Engine instance. + * {@link RegionForwardingUsage} contains information for region addresses assigned to one or more + * region forwarding rules. {@link GlobalForwardingUsage} contains information for global + * addresses assigned to one or more global forwarding rules. + */ + public abstract static class Usage implements Serializable { + + private static final long serialVersionUID = -5028609518171408695L; + + Usage() {} + + /** + * Returns the identities of resources currently using this address. + */ + public abstract List users(); + + final boolean baseEquals(Usage usage) { + return Objects.equals(toPb(), usage.toPb()); + } + + Address toPb() { + return new Address().setUsers(Lists.transform(users(), new Function() { + @Override + public String apply(ResourceId resourceId) { + return resourceId.selfLink(); + } + })); + } + + @SuppressWarnings("unchecked") + static T fromPb(Address addressPb) { + String url = addressPb.getUsers().get(0); + if (InstanceId.matchesUrl(url)) { + return (T) InstanceUsage.fromPb(addressPb); + } else if (RegionForwardingRuleId.matchesUrl(url)) { + return (T) RegionForwardingUsage.fromPb(addressPb); + } else if (GlobalForwardingRuleId.matchesUrl(url)) { + return (T) GlobalForwardingUsage.fromPb(addressPb); + } else { + throw new IllegalArgumentException("Unexpected resource URL for address user"); + } + } + } + + /** + * Usage information for a Google Compute Engine region address assigned to a virtual machine + * instance. + */ + public static final class InstanceUsage extends Usage { + + private static final long serialVersionUID = -5028609518171408695L; + + private final InstanceId instance; + + InstanceUsage(InstanceId instance) { + this.instance = checkNotNull(instance); + } + + /** + * Returns the identity of the instance using the address. + */ + public InstanceId instance() { + return instance; + } + + @Override + public List users() { + return ImmutableList.of(instance); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("instance", instance).toString(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof InstanceUsage && baseEquals((InstanceUsage) obj); + } + + @Override + public int hashCode() { + return Objects.hash(instance); + } + + @SuppressWarnings("unchecked") + static InstanceUsage fromPb(Address addressPb) { + return new InstanceUsage(InstanceId.fromUrl(addressPb.getUsers().get(0))); + } + } + + /** + * Usage information for a Google Compute Engine region address assigned to one or more region + * forwarding rules. + */ + public static final class RegionForwardingUsage extends Usage { + + private static final long serialVersionUID = -4255145869626427363L; + + private final List forwardingRules; + + RegionForwardingUsage(List forwardingRules) { + this.forwardingRules = ImmutableList.copyOf(forwardingRules); + } + + /** + * Returns a list of identities of region forwarding rules that are currently using the address. + */ + public List forwardingRules() { + return forwardingRules; + } + + @Override + public List users() { + return forwardingRules; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("forwardingRules", forwardingRules).toString(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof RegionForwardingUsage && baseEquals((RegionForwardingUsage) obj); + } + + @Override + public int hashCode() { + return Objects.hash(forwardingRules); + } + + @SuppressWarnings("unchecked") + static RegionForwardingUsage fromPb(Address addressPb) { + return new RegionForwardingUsage( + Lists.transform(addressPb.getUsers(), RegionForwardingRuleId.FROM_URL_FUNCTION)); + } + } + + /** + * Usage information for a Google Compute Engine global address assigned to one or more global + * forwarding rules. + */ + public static final class GlobalForwardingUsage extends Usage { + + private static final long serialVersionUID = -2974154224319117433L; + + private final List forwardingRules; + + GlobalForwardingUsage(List forwardingRules) { + this.forwardingRules = ImmutableList.copyOf(forwardingRules); + } + + /** + * Returns a list of identities of global forwarding rules that are currently using the address. + */ + public List forwardingRules() { + return forwardingRules; + } + + @Override + public List users() { + return forwardingRules; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("forwardingRules", forwardingRules).toString(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof GlobalForwardingUsage && baseEquals((GlobalForwardingUsage) obj); + } + + @Override + public int hashCode() { + return Objects.hash(forwardingRules); + } + + @SuppressWarnings("unchecked") + static GlobalForwardingUsage fromPb(Address addressPb) { + return new GlobalForwardingUsage( + Lists.transform(addressPb.getUsers(), GlobalForwardingRuleId.FROM_URL_FUNCTION)); + } + } + + /** + * A builder for {@code AddressInfo} objects. + */ + public abstract static class Builder { + + /** + * Sets the actual IP address. + */ + public abstract Builder address(String address); + + abstract Builder creationTimestamp(Long creationTimestamp); + + /** + * Sets an optional textual description of the address. + */ + public abstract Builder description(String description); + + abstract Builder id(String id); + + public abstract Builder addressId(AddressId addressId); + + abstract Builder status(Status status); + + abstract Builder usage(Usage usage); + + /** + * Creates an {@code AddressInfo} object. + */ + public abstract AddressInfo build(); + } + + static final class BuilderImpl extends Builder { + + private String address; + private Long creationTimestamp; + private String description; + private String id; + private AddressId addressId; + private Status status; + private Usage usage; + + BuilderImpl() {} + + BuilderImpl(AddressInfo addressInfo) { + this.address = addressInfo.address; + this.creationTimestamp = addressInfo.creationTimestamp; + this.description = addressInfo.description; + this.id = addressInfo.id; + this.addressId = addressInfo.addressId; + this.status = addressInfo.status; + this.usage = addressInfo.usage; + } + + BuilderImpl(Address addressPb) { + if (RegionAddressId.matchesUrl(addressPb.getSelfLink())) { + addressId = RegionAddressId.fromUrl(addressPb.getSelfLink()); + } else { + addressId = GlobalAddressId.fromUrl(addressPb.getSelfLink()); + } + address = addressPb.getAddress(); + if (addressPb.getCreationTimestamp() != null) { + creationTimestamp = TIMESTAMP_FORMATTER.parseMillis(addressPb.getCreationTimestamp()); + } + description = addressPb.getDescription(); + if (addressPb.getId() != null) { + id = addressPb.getId().toString(); + } + if (addressPb.getStatus() != null) { + status = Status.valueOf(addressPb.getStatus()); + } + if (addressPb.getUsers() != null && addressPb.getUsers().size() > 0) { + usage = Usage.fromPb(addressPb); + } + } + + @Override + public BuilderImpl address(String address) { + this.address = address; + return this; + } + + @Override + BuilderImpl creationTimestamp(Long creationTimestamp) { + this.creationTimestamp = creationTimestamp; + return this; + } + + @Override + public BuilderImpl description(String description) { + this.description = description; + return this; + } + + @Override + BuilderImpl id(String id) { + this.id = id; + return this; + } + + @Override + public BuilderImpl addressId(AddressId addressId) { + this.addressId = checkNotNull(addressId); + return this; + } + + @Override + BuilderImpl status(Status status) { + this.status = status; + return this; + } + + @Override + BuilderImpl usage(Usage usage) { + this.usage = usage; + return this; + } + + @Override + public AddressInfo build() { + return new AddressInfo(this); + } + } + + AddressInfo(BuilderImpl builder) { + address = builder.address; + creationTimestamp = builder.creationTimestamp; + description = builder.description; + id = builder.id; + addressId = checkNotNull(builder.addressId); + status = builder.status; + usage = builder.usage; + } + + /** + * Returns the static external IP address represented by this object. + */ + public String address() { + return address; + } + + /** + * Returns the creation timestamp in milliseconds since epoch. + */ + public Long creationTimestamp() { + return creationTimestamp; + } + + /** + * Returns an optional textual description of the address. + */ + public String description() { + return description; + } + + /** + * Returns the unique identifier for the address; defined by the service. + */ + public String id() { + return id; + } + + /** + * Returns the address identity. Returns {@link GlobalAddressId} for a global address, returns + * {@link RegionAddressId} for a region address. + */ + @SuppressWarnings("unchecked") + public T addressId() { + return (T) addressId; + } + + /** + * Returns the status of the address. + */ + public Status status() { + return status; + } + + /** + * Returns the usage information of the address. Returns an {@link InstanceUsage} object for + * region addresses that are assigned to VM instances. Returns a {@link RegionForwardingUsage} + * object for region addresses assigned to region forwarding rules. Returns a + * {@link GlobalForwardingUsage} object for global addresses assigned to global forwarding rules. + * Returns {@code null} if the address is not in use. + */ + @SuppressWarnings("unchecked") + public T usage() { + return (T) usage; + } + + /** + * Returns a builder for the {@code AddressInfo} object. + */ + public Builder toBuilder() { + return new BuilderImpl(this); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("address", address) + .add("creationTimestamp", creationTimestamp) + .add("description", description) + .add("id", id) + .add("addressId", addressId) + .add("status", status) + .add("usage", usage) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(address, creationTimestamp, description, id, addressId, status, usage); + } + + @Override + public boolean equals(Object obj) { + return obj != null + && obj.getClass().equals(AddressInfo.class) + && Objects.equals(toPb(), ((AddressInfo) obj).toPb()); + } + + AddressInfo setProjectId(String projectId) { + if (addressId().project() != null) { + return this; + } + return toBuilder().addressId(addressId.setProjectId(projectId)).build(); + } + + Address toPb() { + Address addressPb = usage != null ? usage.toPb() : new Address(); + addressPb.setAddress(address); + if (creationTimestamp != null) { + addressPb.setCreationTimestamp(TIMESTAMP_FORMATTER.print(creationTimestamp)); + } + addressPb.setDescription(description); + if (id != null) { + addressPb.setId(new BigInteger(id)); + } + addressPb.setName(addressId.address()); + if (addressId.type() == AddressId.Type.REGION) { + addressPb.setRegion(this.addressId().regionId().selfLink()); + } + if (status != null) { + addressPb.setStatus(status.name()); + } + addressPb.setSelfLink(addressId.selfLink()); + return addressPb; + } + + /** + * Returns a builder for the {@code AddressInfo} object given it's identity. + */ + public static Builder builder(AddressId addressId) { + return new BuilderImpl().addressId(addressId); + } + + /** + * Returns an {@code AddressInfo} object for the provided identity. + */ + public static AddressInfo of(AddressId addressId) { + return builder(addressId).build(); + } + + /** + * Returns an {@code AddressInfo} object for the provided name. The object corresponds to a global + * address. + */ + public static AddressInfo of(String name) { + return of(GlobalAddressId.of(name)); + } + + /** + * Returns an {@code AddressInfo} object for the provided region identity and name. The object + * corresponds to a region address. + */ + public static AddressInfo of(RegionId regionId, String name) { + return of(RegionAddressId.of(regionId, name)); + } + + /** + * Returns an {@code AddressInfo} object for the provided region and address names. The object + * corresponds to a region address. + */ + public static AddressInfo of(String region, String name) { + return of(RegionAddressId.of(region, name)); + } + + static AddressInfo fromPb(Address addressPb) { + return new BuilderImpl(addressPb).build(); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java index 8d707a598c32..815b5ebe49e6 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Compute.java @@ -275,6 +275,253 @@ static String selector(OperationField... fields) { } } + /** + * Fields of a Compute Engine Address resource. + * + * @see Region + * Address Resource + * @see + * Global Address Resource + */ + enum AddressField { + ADDRESS("address"), + CREATION_TIMESTAMP("creationTimestamp"), + DESCRIPTION("description"), + ID("id"), + NAME("name"), + REGION("region"), + SELF_LINK("selfLink"), + STATUS("status"), + USERS("users"); + + private final String selector; + + AddressField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(AddressField... fields) { + Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1); + fieldStrings.add(SELF_LINK.selector()); + for (AddressField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + + /** + * Fields of a Compute Engine Disk resource. + * + * @see Disk + * Resource + */ + enum DiskField { + CREATION_TIMESTAMP("creationTimestamp"), + DESCRIPTION("description"), + ID("id"), + LAST_ATTACH_TIMESTAMP("lastAttachTimestamp"), + LAST_DETACH_TIMESTAMP("lastDetachTimestamp"), + LICENSES("licenses"), + NAME("name"), + OPTIONS("options"), + SELF_LINK("selfLink"), + SIZE_GB("sizeGb"), + SOURCE_IMAGE("sourceImage"), + SOURCE_IMAGE_ID("sourceImageId"), + SOURCE_SNAPSHOT("sourceSnapshot"), + SOURCE_SNAPSHOT_ID("sourceSnapshotId"), + STATUS("status"), + TYPE("type"), + USERS("users"), + ZONE("zone"); + + private final String selector; + + DiskField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(DiskField... fields) { + Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 4); + fieldStrings.add(SELF_LINK.selector()); + fieldStrings.add(TYPE.selector()); + fieldStrings.add(SOURCE_IMAGE.selector()); + fieldStrings.add(SOURCE_SNAPSHOT.selector()); + for (DiskField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + + /** + * Fields of a Compute Engine Snapshot resource. + * + * @see + * Snapshot Resource + */ + enum SnapshotField { + CREATION_TIMESTAMP("creationTimestamp"), + DESCRIPTION("description"), + DISK_SIZE_GB("diskSizeGb"), + ID("id"), + LICENSES("licenses"), + NAME("name"), + SELF_LINK("selfLink"), + SOURCE_DISK("sourceDisk"), + SOURCE_DISK_ID("sourceDiskId"), + STATUS("status"), + STORAGE_BYTES("storageBytes"), + STORAGE_BYTES_STATUS("storageBytesStatus"); + + private final String selector; + + SnapshotField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(SnapshotField... fields) { + Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1); + fieldStrings.add(SELF_LINK.selector()); + for (SnapshotField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + + /** + * Fields of a Compute Engine Image resource. + * + * @see Image + * Resource + */ + enum ImageField { + ARCHIVE_SIZE_BYTES("archiveSizeBytes"), + CREATION_TIMESTAMP("creationTimestamp"), + DEPRECATED("deprecated"), + DESCRIPTION("description"), + DISK_SIZE_GB("diskSizeGb"), + ID("id"), + LICENSES("licenses"), + NAME("name"), + RAW_DISK("rawDisk"), + SELF_LINK("selfLink"), + SOURCE_DISK("sourceDisk"), + SOURCE_DISK_ID("sourceDiskId"), + SOURCE_TYPE("sourceType"); + + private final String selector; + + ImageField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(ImageField... fields) { + Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 3); + fieldStrings.add(SELF_LINK.selector()); + fieldStrings.add(SOURCE_DISK.selector()); + fieldStrings.add(RAW_DISK.selector()); + for (ImageField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + + /** + * Fields of a Compute Engine Subnetwork resource. + * + * @see + * Subnetwork Resource + */ + enum SubnetworkField { + CREATION_TIMESTAMP("creationTimestamp"), + DESCRIPTION("description"), + GATEWAY_ADDRESS("gatewayAddress"), + ID("id"), + IP_CIDR_RANGE("ipCidrRange"), + NAME("name"), + NETWORK("network"), + REGION("region"), + SELF_LINK("selfLink"); + + private final String selector; + + SubnetworkField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(SubnetworkField... fields) { + Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 1); + fieldStrings.add(SELF_LINK.selector()); + for (SubnetworkField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + + /** + * Fields of a Compute Engine Network resource. + * + * @see + * Network Resource + */ + enum NetworkField { + IPV4_RANGE("IPv4Range"), + AUTO_CREATE_SUBNETWORKS("autoCreateSubnetworks"), + CREATION_TIMESTAMP("creationTimestamp"), + DESCRIPTION("description"), + GATEWAY_IPV4("gatewayIPv4"), + ID("id"), + NAME("name"), + SELF_LINK("selfLink"), + SUBNETWORKS("subnetworks"); + + private final String selector; + + NetworkField(String selector) { + this.selector = selector; + } + + public String selector() { + return selector; + } + + static String selector(NetworkField... fields) { + Set fieldStrings = Sets.newHashSetWithExpectedSize(fields.length + 3); + fieldStrings.add(SELF_LINK.selector()); + fieldStrings.add(IPV4_RANGE.selector()); + fieldStrings.add(AUTO_CREATE_SUBNETWORKS.selector()); + for (NetworkField field : fields) { + fieldStrings.add(field.selector()); + } + return Joiner.on(',').join(fieldStrings); + } + } + /** * Base class for list filters. */ @@ -540,6 +787,40 @@ public static OperationFilter notEquals(OperationField field, long value) { } } + /** + * Class for filtering address lists. + */ + class AddressFilter extends ListFilter { + + private static final long serialVersionUID = -227481644259653765L; + + AddressFilter(AddressField field, ComparisonOperator operator, Object value) { + super(field.selector(), operator, value); + } + + /** + * Returns an equals filter for the given field and string value. For string fields, + * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must + * match the entire field. + * + * @see RE2 + */ + public static AddressFilter equals(AddressField field, String value) { + return new AddressFilter(checkNotNull(field), ComparisonOperator.EQ, checkNotNull(value)); + } + + /** + * Returns a not-equals filter for the given field and string value. For string fields, + * {@code value} is interpreted as a regular expression using RE2 syntax. {@code value} must + * match the entire field. + * + * @see RE2 + */ + public static AddressFilter notEquals(AddressField field, String value) { + return new AddressFilter(checkNotNull(field), ComparisonOperator.NE, checkNotNull(value)); + } + } + /** * Class for specifying disk type get options. */ @@ -590,7 +871,7 @@ public static DiskTypeListOption pageSize(long pageSize) { /** * Returns an option to specify the page token from which to start listing disk types. */ - public static DiskTypeListOption startPageToken(String pageToken) { + public static DiskTypeListOption pageToken(String pageToken) { return new DiskTypeListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); } @@ -635,7 +916,7 @@ public static DiskTypeAggregatedListOption pageSize(long pageSize) { /** * Returns an option to specify the page token from which to start listing disk types. */ - public static DiskTypeAggregatedListOption startPageToken(String pageToken) { + public static DiskTypeAggregatedListOption pageToken(String pageToken) { return new DiskTypeAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); } } @@ -690,7 +971,7 @@ public static MachineTypeListOption pageSize(long pageSize) { /** * Returns an option to specify the page token from which to start listing machine types. */ - public static MachineTypeListOption startPageToken(String pageToken) { + public static MachineTypeListOption pageToken(String pageToken) { return new MachineTypeListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); } @@ -735,7 +1016,7 @@ public static MachineTypeAggregatedListOption pageSize(long pageSize) { /** * Returns an option to specify the page token from which to start listing machine types. */ - public static MachineTypeAggregatedListOption startPageToken(String pageToken) { + public static MachineTypeAggregatedListOption pageToken(String pageToken) { return new MachineTypeAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); } } @@ -790,7 +1071,7 @@ public static RegionListOption pageSize(long pageSize) { /** * Returns an option to specify the page token from which to start listing regions. */ - public static RegionListOption startPageToken(String pageToken) { + public static RegionListOption pageToken(String pageToken) { return new RegionListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); } @@ -857,7 +1138,7 @@ public static ZoneListOption pageSize(long pageSize) { /** * Returns an option to specify the page token from which to start listing zones. */ - public static ZoneListOption startPageToken(String pageToken) { + public static ZoneListOption pageToken(String pageToken) { return new ZoneListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); } @@ -946,7 +1227,7 @@ public static OperationListOption pageSize(long pageSize) { /** * Returns an option to specify the page token from which to start listing operations. */ - public static OperationListOption startPageToken(String pageToken) { + public static OperationListOption pageToken(String pageToken) { return new OperationListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); } @@ -963,6 +1244,106 @@ public static OperationListOption fields(OperationField... fields) { } } + /** + * Class for specifying address get options. + */ + class AddressOption extends Option { + + private static final long serialVersionUID = -5755491818692494389L; + + private AddressOption(ComputeRpc.Option option, Object value) { + super(option, value); + } + + /** + * Returns an option to specify the address' fields to be returned by the RPC call. If this + * option is not provided, all address' fields are returned. {@code AddressOption.fields} can be + * used to specify only the fields of interest. {@link Address#addressId()} is always + * returned, even if not specified. + */ + public static AddressOption fields(AddressField... fields) { + return new AddressOption(ComputeRpc.Option.FIELDS, AddressField.selector(fields)); + } + } + + /** + * Class for specifying address list options. + */ + class AddressListOption extends Option { + + private static final long serialVersionUID = -4281322966374929346L; + + private AddressListOption(ComputeRpc.Option option, Object value) { + super(option, value); + } + + /** + * Returns an option to specify a filter on the addresses being listed. + */ + public static AddressListOption filter(AddressFilter filter) { + return new AddressListOption(ComputeRpc.Option.FILTER, filter.toPb()); + } + + /** + * Returns an option to specify the maximum number of addresses returned per page. + */ + public static AddressListOption pageSize(long pageSize) { + return new AddressListOption(ComputeRpc.Option.MAX_RESULTS, pageSize); + } + + /** + * Returns an option to specify the page token from which to start listing addresses. + */ + public static AddressListOption pageToken(String pageToken) { + return new AddressListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); + } + + /** + * Returns an option to specify the address' fields to be returned by the RPC call. If this + * option is not provided, all address' fields are returned. {@code AddressListOption.fields} + * can be used to specify only the fields of interest. {@link Address#addressId()} is always + * returned, even if not specified. + */ + public static AddressListOption fields(AddressField... fields) { + StringBuilder builder = new StringBuilder(); + builder.append("items(").append(AddressField.selector(fields)).append("),nextPageToken"); + return new AddressListOption(ComputeRpc.Option.FIELDS, builder.toString()); + } + } + + /** + * Class for specifying address aggregated list options. + */ + class AddressAggregatedListOption extends Option { + + private static final long serialVersionUID = -95538941541279561L; + + private AddressAggregatedListOption(ComputeRpc.Option option, Object value) { + super(option, value); + } + + /** + * Returns an option to specify a filter on the addresses being listed. + */ + public static AddressAggregatedListOption filter(AddressFilter filter) { + return new AddressAggregatedListOption(ComputeRpc.Option.FILTER, filter.toPb()); + } + + /** + * Returns an option to specify the maximum number of addresses returned per page. + */ + public static AddressAggregatedListOption pageSize(long pageSize) { + return new AddressAggregatedListOption(ComputeRpc.Option.MAX_RESULTS, pageSize); + } + + /** + * Returns an option to specify the page token from which to start listing addresses. + */ + public static AddressAggregatedListOption pageToken(String pageToken) { + return new AddressAggregatedListOption(ComputeRpc.Option.PAGE_TOKEN, pageToken); + } + } + /** * Returns the requested disk type or {@code null} if not found. * @@ -1099,4 +1480,49 @@ public static OperationListOption fields(OperationField... fields) { * @throws ComputeException upon failure */ boolean delete(OperationId operation); + + /** + * Returns the requested address or {@code null} if not found. + * + * @throws ComputeException upon failure + */ + Address get(AddressId addressId, AddressOption... options); + + /** + * Creates a new address. + * + * @return an operation for address' creation + * @throws ComputeException upon failure + */ + Operation create(AddressInfo address, OperationOption... options); + + /** + * Lists the global addresses. + * + * @throws ComputeException upon failure + */ + Page
listGlobalAddresses(AddressListOption... options); + + /** + * Lists the region addresses for the provided region. + * + * @throws ComputeException upon failure + */ + Page
listRegionAddresses(String region, AddressListOption... options); + + /** + * Lists all addresses. + * + * @throws ComputeException upon failure + */ + Page
listAddresses(AddressAggregatedListOption... options); + + /** + * Deletes the requested address. + * + * @return an operation if the request was issued correctly, {@code null} if the address was not + * found + * @throws ComputeException upon failure + */ + Operation delete(AddressId addressId, OperationOption... options); } diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java index 5e6c4bc869a6..838816a035e0 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ComputeImpl.java @@ -214,6 +214,65 @@ public Page nextPage() { } } + private static class GlobalAddressPageFetcher implements NextPageFetcher
{ + + private static final long serialVersionUID = -3832055341507574454L; + private final Map requestOptions; + private final ComputeOptions serviceOptions; + + GlobalAddressPageFetcher(ComputeOptions serviceOptions, String cursor, + Map optionMap) { + this.requestOptions = + PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap); + this.serviceOptions = serviceOptions; + } + + @Override + public Page
nextPage() { + return listGlobalAddresses(serviceOptions, requestOptions); + } + } + + private static class RegionAddressPageFetcher implements NextPageFetcher
{ + + private static final long serialVersionUID = 7080596594494397027L; + private final Map requestOptions; + private final ComputeOptions serviceOptions; + private final String region; + + RegionAddressPageFetcher(String region, ComputeOptions serviceOptions, String cursor, + Map optionMap) { + this.requestOptions = + PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap); + this.serviceOptions = serviceOptions; + this.region = region; + } + + @Override + public Page
nextPage() { + return listRegionAddresses(region, serviceOptions, requestOptions); + } + } + + private static class AggregatedAddressPageFetcher implements NextPageFetcher
{ + + private static final long serialVersionUID = -5798942282919494950L; + private final Map requestOptions; + private final ComputeOptions serviceOptions; + + AggregatedAddressPageFetcher(ComputeOptions serviceOptions, String cursor, + Map optionMap) { + this.requestOptions = + PageImpl.nextRequestOptions(ComputeRpc.Option.PAGE_TOKEN, cursor, optionMap); + this.serviceOptions = serviceOptions; + } + + @Override + public Page
nextPage() { + return listAddresses(serviceOptions, requestOptions); + } + } + private final ComputeRpc computeRpc; ComputeImpl(ComputeOptions options) { @@ -555,6 +614,16 @@ public com.google.api.services.compute.model.Operation call() { } } + private static Function + operationFromPb(final ComputeOptions serviceOptions) { + return new Function() { + @Override + public Operation apply(com.google.api.services.compute.model.Operation operation) { + return Operation.fromPb(serviceOptions.service(), operation); + } + }; + } + @Override public Page listGlobalOperations(OperationListOption... options) { return listGlobalOperations(options(), optionMap(options)); @@ -575,13 +644,7 @@ Iterable> call() { String cursor = result.x(); Iterable operations = Iterables.transform( result.y() == null ? ImmutableList.of() - : result.y(), - new Function() { - @Override - public Operation apply(com.google.api.services.compute.model.Operation operation) { - return Operation.fromPb(serviceOptions.service(), operation); - } - }); + : result.y(), operationFromPb(serviceOptions)); return new PageImpl<>(new GlobalOperationPageFetcher(serviceOptions, cursor, optionsMap), cursor, operations); } catch (RetryHelper.RetryHelperException e) { @@ -609,13 +672,7 @@ Iterable> call() { String cursor = result.x(); Iterable operations = Iterables.transform( result.y() == null ? ImmutableList.of() - : result.y(), - new Function() { - @Override - public Operation apply(com.google.api.services.compute.model.Operation operation) { - return Operation.fromPb(serviceOptions.service(), operation); - } - }); + : result.y(), operationFromPb(serviceOptions)); return new PageImpl<>(new RegionOperationPageFetcher(region, serviceOptions, cursor, optionsMap), cursor, operations); } catch (RetryHelper.RetryHelperException e) { @@ -643,13 +700,7 @@ Iterable> call() { String cursor = result.x(); Iterable operations = Iterables.transform( result.y() == null ? ImmutableList.of() - : result.y(), - new Function() { - @Override - public Operation apply(com.google.api.services.compute.model.Operation operation) { - return Operation.fromPb(serviceOptions.service(), operation); - } - }); + : result.y(), operationFromPb(serviceOptions)); return new PageImpl<>(new ZoneOperationPageFetcher(zone, serviceOptions, cursor, optionsMap), cursor, operations); } catch (RetryHelper.RetryHelperException e) { @@ -684,6 +735,185 @@ public Boolean call() { } } + @Override + public Address get(final AddressId addressId, AddressOption... options) { + final Map optionsMap = optionMap(options); + try { + com.google.api.services.compute.model.Address answer = + runWithRetries(new Callable() { + @Override + public com.google.api.services.compute.model.Address call() { + switch (addressId.type()) { + case REGION: + RegionAddressId regionAddressId = (RegionAddressId) addressId; + return computeRpc.getRegionAddress(regionAddressId.region(), + regionAddressId.address(), optionsMap); + case GLOBAL: + return computeRpc.getGlobalAddress(addressId.address(), optionsMap); + default: + throw new IllegalArgumentException("Unexpected address identity type"); + } + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Address.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation create(final AddressInfo address, OperationOption... options) { + final com.google.api.services.compute.model.Address addressPb = + address.setProjectId(options().projectId()).toPb(); + final Map optionsMap = optionMap(options); + try { + return Operation.fromPb(this, + runWithRetries(new Callable() { + @Override + public com.google.api.services.compute.model.Operation call() { + switch (address.addressId().type()) { + case REGION: + RegionAddressId regionAddressId = address.addressId(); + return computeRpc.createRegionAddress(regionAddressId.region(), addressPb, + optionsMap); + case GLOBAL: + return computeRpc.createGlobalAddress(addressPb, optionsMap); + default: + throw new IllegalArgumentException("Unexpected address identity type"); + } + } + }, options().retryParams(), EXCEPTION_HANDLER)); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + private static Function addressFromPb( + final ComputeOptions serviceOptions) { + return new Function() { + @Override + public Address apply(com.google.api.services.compute.model.Address address) { + return Address.fromPb(serviceOptions.service(), address); + } + }; + } + + @Override + public Page
listGlobalAddresses(AddressListOption... options) { + return listGlobalAddresses(options(), optionMap(options)); + } + + private static Page
listGlobalAddresses(final ComputeOptions serviceOptions, + final Map optionsMap) { + try { + ComputeRpc.Tuple> result = + runWithRetries(new Callable>>() { + @Override + public ComputeRpc.Tuple> call() { + return serviceOptions.rpc().listGlobalAddresses(optionsMap); + } + }, serviceOptions.retryParams(), EXCEPTION_HANDLER); + String cursor = result.x(); + Iterable
operations = Iterables.transform( + result.y() == null ? ImmutableList.of() + : result.y(), addressFromPb(serviceOptions)); + return new PageImpl<>(new GlobalAddressPageFetcher(serviceOptions, cursor, optionsMap), + cursor, operations); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Page
listRegionAddresses(String region, AddressListOption... options) { + return listRegionAddresses(region, options(), optionMap(options)); + } + + private static Page
listRegionAddresses(final String region, + final ComputeOptions serviceOptions, final Map optionsMap) { + try { + ComputeRpc.Tuple> result = + runWithRetries(new Callable>>() { + @Override + public ComputeRpc.Tuple> call() { + return serviceOptions.rpc().listRegionAddresses(region, optionsMap); + } + }, serviceOptions.retryParams(), EXCEPTION_HANDLER); + String cursor = result.x(); + Iterable
operations = Iterables.transform( + result.y() == null ? ImmutableList.of() + : result.y(), addressFromPb(serviceOptions)); + return new PageImpl<>(new RegionAddressPageFetcher(region, serviceOptions, cursor, + optionsMap), cursor, operations); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Page
listAddresses(AddressAggregatedListOption... options) { + return listAddresses(options(), optionMap(options)); + } + + private static Page
listAddresses(final ComputeOptions serviceOptions, + final Map optionsMap) { + try { + ComputeRpc.Tuple> result = + runWithRetries(new Callable>>() { + @Override + public ComputeRpc.Tuple> call() { + return serviceOptions.rpc().listAddresses(optionsMap); + } + }, serviceOptions.retryParams(), EXCEPTION_HANDLER); + String cursor = result.x(); + Iterable
operations = Iterables.transform( + result.y() == null ? ImmutableList.of() + : result.y(), + new Function() { + @Override + public Address apply(com.google.api.services.compute.model.Address address) { + return Address.fromPb(serviceOptions.service(), address); + } + }); + return new PageImpl<>(new AggregatedAddressPageFetcher(serviceOptions, cursor, + optionsMap), cursor, operations); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + + @Override + public Operation delete(final AddressId addressId, OperationOption... options) { + final Map optionsMap = optionMap(options); + try { + com.google.api.services.compute.model.Operation answer = + runWithRetries(new Callable() { + @Override + public com.google.api.services.compute.model.Operation call() { + switch (addressId.type()) { + case REGION: + RegionAddressId regionAddressId = (RegionAddressId) addressId; + return computeRpc.deleteRegionAddress(regionAddressId.region(), + regionAddressId.address(), optionsMap); + case GLOBAL: + return computeRpc.deleteGlobalAddress(addressId.address(), optionsMap); + default: + throw new IllegalArgumentException("Unexpected address identity type"); + } + } + }, options().retryParams(), EXCEPTION_HANDLER); + return answer == null ? null : Operation.fromPb(this, answer); + } catch (RetryHelper.RetryHelperException e) { + throw ComputeException.translateAndThrow(e); + } + } + private Map optionMap(Option... options) { Map optionMap = Maps.newEnumMap(ComputeRpc.Option.class); for (Option option : options) { diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java index 0991a9d5d666..f6c8342a0f1c 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskType.java @@ -137,7 +137,7 @@ public DiskTypeId diskTypeId() { } /** - * Returns an unique identifier for the disk type; defined by the service. + * Returns the unique identifier for the disk type; defined by the service. */ public String id() { return id; diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java index cdf1fd42eedc..039565ec827f 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskTypeId.java @@ -28,7 +28,7 @@ /** * Identity for a Google Compute Engine disk type. */ -public final class DiskTypeId extends ZoneResourceId { +public final class DiskTypeId extends ResourceId { static final Function FROM_URL_FUNCTION = new Function() { @Override @@ -43,14 +43,16 @@ public String apply(DiskTypeId diskTypeId) { } }; - private static final String REGEX = ZoneResourceId.REGEX + "diskTypes/([^/]+)"; + private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/diskTypes/([^/]+)"; private static final Pattern PATTERN = Pattern.compile(REGEX); private static final long serialVersionUID = 7337881474103686219L; + private final String zone; private final String diskType; private DiskTypeId(String project, String zone, String diskType) { - super(project, zone); + super(project); + this.zone = checkNotNull(zone); this.diskType = checkNotNull(diskType); } @@ -61,26 +63,47 @@ public String diskType() { return diskType; } + /** + * Returns the name of the zone this disk type belongs to. + */ + public String zone() { + return zone; + } + + /** + * Returns the identity of the zone this disk type belongs to. + */ + public ZoneId zoneId() { + return ZoneId.of(project(), zone); + } + @Override public String selfLink() { - return super.selfLink() + "/diskTypes/" + diskType; + return super.selfLink() + "/zones/" + zone + "/diskTypes/" + diskType; } @Override MoreObjects.ToStringHelper toStringHelper() { - return super.toStringHelper().add("diskType", diskType); + return super.toStringHelper().add("zone", zone).add("diskType", diskType); } @Override public int hashCode() { - return Objects.hash(super.baseHashCode(), diskType); + return Objects.hash(super.baseHashCode(), zone, diskType); } @Override public boolean equals(Object obj) { - return obj instanceof DiskTypeId - && baseEquals((DiskTypeId) obj) - && Objects.equals(diskType, ((DiskTypeId) obj).diskType); + if (obj == this) { + return true; + } + if (!(obj instanceof DiskTypeId)) { + return false; + } + DiskTypeId other = (DiskTypeId) obj; + return baseEquals(other) + && Objects.equals(zone, other.zone) + && Objects.equals(diskType, other.diskType); } @Override @@ -88,7 +111,7 @@ DiskTypeId setProjectId(String projectId) { if (project() != null) { return this; } - return DiskTypeId.of(projectId, zone(), diskType); + return DiskTypeId.of(projectId, zone, diskType); } /** diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ForwardingRuleId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ForwardingRuleId.java new file mode 100644 index 000000000000..546dcf596246 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ForwardingRuleId.java @@ -0,0 +1,93 @@ +/* + * 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.gcloud.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.MoreObjects; + +import java.util.Objects; + +/** + * Base class for Google Compute Engine forwarding rule identities. + */ +public abstract class ForwardingRuleId extends ResourceId { + + private static final long serialVersionUID = -4352410760458355391L; + + private final String rule; + + ForwardingRuleId(String project, String rule) { + super(project); + this.rule = checkNotNull(rule); + } + + /** + * Possible types for a Google Compute Engine forwarding rule identity. + */ + enum Type { + /** + * Global forwarding rules are used to forward traffic to the correct load balancer for HTTP(S) + * load balancing. + */ + GLOBAL, + + /** + * Region forwarding rules are used to forward traffic to the correct pool of target virtual + * machines. + */ + REGION + } + + /** + * Returns the type of this forwarding rule identity. + */ + public abstract Type type(); + + /** + * Returns the name of the forwarding rule. The forwarding rule name must be 1-63 characters long + * and comply with RFC1035. Specifically, the name must match the regular expression + * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter, + * and all following characters must be a dash, lowercase letter, or digit, except the last + * character, which cannot be a dash. + * + * @see RFC1035 + */ + public String rule() { + return rule; + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("rule", rule); + } + + @Override + final int baseHashCode() { + return Objects.hash(super.baseHashCode(), rule); + } + + @Override + final boolean baseEquals(ResourceId resourceId) { + return resourceId instanceof ForwardingRuleId + && super.baseEquals(resourceId) + && Objects.equals(rule, ((ForwardingRuleId) resourceId).rule); + } + + @Override + abstract ForwardingRuleId setProjectId(String projectId); +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalAddressId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalAddressId.java new file mode 100644 index 000000000000..dcda73ac7370 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalAddressId.java @@ -0,0 +1,104 @@ +/* + * 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.gcloud.compute; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Identity for a Google Compute Engine global address. + */ +public final class GlobalAddressId extends AddressId { + + private static final String REGEX = ResourceId.REGEX + "global/addresses/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + private static final long serialVersionUID = -2950815290049218593L; + + private GlobalAddressId(String project, String address) { + super(project, address); + } + + @Override + public Type type() { + return Type.GLOBAL; + } + + @Override + public String selfLink() { + return super.selfLink() + "/global/addresses/" + address(); + } + + @Override + public int hashCode() { + return baseHashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof GlobalAddressId && baseEquals((GlobalAddressId) obj); + } + + @Override + GlobalAddressId setProjectId(String projectId) { + if (project() != null) { + return this; + } + return GlobalAddressId.of(projectId, address()); + } + + /** + * Returns an address identity given the address name. The address name must be 1-63 characters + * long and comply with RFC1035. Specifically, the name must match the regular expression + * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter, + * and all following characters must be a dash, lowercase letter, or digit, except the last + * character, which cannot be a dash. + * + * @see RFC1035 + */ + public static GlobalAddressId of(String address) { + return new GlobalAddressId(null, address); + } + + /** + * Returns an address identity given project and address names. The address name must be 1-63 + * characters long and comply with RFC1035. Specifically, the name must match the regular + * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static GlobalAddressId of(String project, String address) { + return new GlobalAddressId(project, address); + } + + /** + * Returns {@code true} if the provided string matches the expected format of a global address + * URL. Returns {@code false} otherwise. + */ + static boolean matchesUrl(String url) { + return PATTERN.matcher(url).matches(); + } + + static GlobalAddressId fromUrl(String url) { + Matcher matcher = PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException(url + " is not a valid global address URL"); + } + return GlobalAddressId.of(matcher.group(1), matcher.group(2)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalForwardingRuleId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalForwardingRuleId.java new file mode 100644 index 000000000000..1b37e9a1adef --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalForwardingRuleId.java @@ -0,0 +1,121 @@ +/* + * 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.gcloud.compute; + +import com.google.common.base.Function; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Identity for a Google Compute Engine global forwarding rule. + */ +public final class GlobalForwardingRuleId extends ForwardingRuleId { + + static final Function FROM_URL_FUNCTION = + new Function() { + @Override + public GlobalForwardingRuleId apply(String pb) { + return GlobalForwardingRuleId.fromUrl(pb); + } + }; + static final Function TO_URL_FUNCTION = + new Function() { + @Override + public String apply(GlobalForwardingRuleId forwardingRuleId) { + return forwardingRuleId.selfLink(); + } + }; + + private static final String REGEX = ResourceId.REGEX + "global/forwardingRules/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + private static final long serialVersionUID = -2648031793037534254L; + + private GlobalForwardingRuleId(String project, String rule) { + super(project, rule); + } + + @Override + public Type type() { + return Type.GLOBAL; + } + + @Override + public String selfLink() { + return super.selfLink() + "/global/forwardingRules/" + rule(); + } + + @Override + public int hashCode() { + return baseHashCode(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof GlobalForwardingRuleId && baseEquals((GlobalForwardingRuleId) obj); + } + + @Override + GlobalForwardingRuleId setProjectId(String projectId) { + if (project() != null) { + return this; + } + return GlobalForwardingRuleId.of(projectId, rule()); + } + + /** + * Returns a forwarding rule identity given the rule name. The forwarding rule name must be 1-63 + * characters long and comply with RFC1035. Specifically, the name must match the regular + * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static GlobalForwardingRuleId of(String rule) { + return new GlobalForwardingRuleId(null, rule); + } + + /** + * Returns a forwarding rule identity given the project rule names. The forwarding rule name must + * be 1-63 characters long and comply with RFC1035. Specifically, the name must match the regular + * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static GlobalForwardingRuleId of(String project, String rule) { + return new GlobalForwardingRuleId(project, rule); + } + + /** + * Returns {@code true} if the provided string matches the expected format of a global forwarding + * rule URL. Returns {@code false} otherwise. + */ + static boolean matchesUrl(String url) { + return PATTERN.matcher(url).matches(); + } + + static GlobalForwardingRuleId fromUrl(String url) { + Matcher matcher = PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException(url + " is not a valid global forwarding rule URL"); + } + return GlobalForwardingRuleId.of(matcher.group(1), matcher.group(2)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java index c12e24c903cc..343b0cacc94c 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/GlobalOperationId.java @@ -16,28 +16,20 @@ package com.google.gcloud.compute; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.MoreObjects; - -import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Identity for a Google Compute Engine global operation. */ -public class GlobalOperationId extends ResourceId implements OperationId { +public final class GlobalOperationId extends OperationId { private static final String REGEX = ResourceId.REGEX + "global/operations/([^/]+)"; private static final Pattern PATTERN = Pattern.compile(REGEX); private static final long serialVersionUID = 3945756772641577962L; - private final String operation; - private GlobalOperationId(String project, String operation) { - super(project); - this.operation = checkNotNull(operation); + super(project, operation); } @Override @@ -45,31 +37,19 @@ public Type type() { return Type.GLOBAL; } - @Override - public String operation() { - return operation; - } - @Override public String selfLink() { - return super.selfLink() + "/global/operations/" + operation; - } - - @Override - MoreObjects.ToStringHelper toStringHelper() { - return super.toStringHelper().add("operation", operation); + return super.selfLink() + "/global/operations/" + operation(); } @Override public int hashCode() { - return Objects.hash(baseHashCode(), operation); + return baseHashCode(); } @Override public boolean equals(Object obj) { - return obj instanceof GlobalOperationId - && baseEquals((GlobalOperationId) obj) - && Objects.equals(operation, ((GlobalOperationId) obj).operation); + return obj instanceof GlobalOperationId && baseEquals((GlobalOperationId) obj); } @Override @@ -77,7 +57,7 @@ GlobalOperationId setProjectId(String projectId) { if (project() != null) { return this; } - return GlobalOperationId.of(projectId, operation); + return GlobalOperationId.of(projectId, operation()); } /** diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/InstanceId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/InstanceId.java new file mode 100644 index 000000000000..408d95e641b4 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/InstanceId.java @@ -0,0 +1,177 @@ +/* + * 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.gcloud.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Identity for a Google Compute Engine virtual machine instance. + */ +public final class InstanceId extends ResourceId { + + static final Function FROM_URL_FUNCTION = new Function() { + @Override + public InstanceId apply(String pb) { + return InstanceId.fromUrl(pb); + } + }; + static final Function TO_URL_FUNCTION = new Function() { + @Override + public String apply(InstanceId instanceId) { + return instanceId.selfLink(); + } + }; + + private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/instances/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + private static final long serialVersionUID = -2787043125223159922L; + + private final String zone; + private final String instance; + + private InstanceId(String project, String zone, String instance) { + super(project); + this.zone = checkNotNull(zone); + this.instance = checkNotNull(instance); + } + + /** + * Returns the name of the instance. The name must be 1-63 characters long and comply with + * RFC1035. Specifically, the name must match the regular expression + * {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a lowercase letter, + * and all following characters must be a dash, lowercase letter, or digit, except the last + * character, which cannot be a dash. + * + * @see RFC1035 + */ + public String instance() { + return instance; + } + + /** + * Returns the name of the zone this instance belongs to. + */ + public String zone() { + return zone; + } + + /** + * Returns the identity of the zone this instance belongs to. + */ + public ZoneId zoneId() { + return ZoneId.of(project(), zone); + } + + @Override + public String selfLink() { + return super.selfLink() + "/zones/" + zone + "/instances/" + instance; + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return MoreObjects.toStringHelper(this).add("zone", zone).add("instance", instance); + } + + @Override + public int hashCode() { + return Objects.hash(super.baseHashCode(), zone, instance); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof InstanceId)) { + return false; + } + InstanceId other = (InstanceId) obj; + return baseEquals(other) + && Objects.equals(zone, other.zone) + && Objects.equals(instance, other.instance); + } + + @Override + InstanceId setProjectId(String projectId) { + if (project() != null) { + return this; + } + return InstanceId.of(projectId, zone, instance); + } + + /** + * Returns an instance identity given the zone identity and the instance name. The instance name + * must be 1-63 characters long and comply with RFC1035. Specifically, the name must match the + * regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static InstanceId of(ZoneId zoneId, String instance) { + return new InstanceId(zoneId.project(), zoneId.zone(), instance); + } + + /** + * Returns an instance identity given the zone and instance names. The instance name must be 1-63 + * characters long and comply with RFC1035. Specifically, the name must match the regular + * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static InstanceId of(String zone, String instance) { + return new InstanceId(null, zone, instance); + } + + /** + * Returns an instance identity given project, zone and instance names. The instance name must be + * 1-63 characters long and comply with RFC1035. Specifically, the name must match the regular + * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static InstanceId of(String project, String zone, String instance) { + return new InstanceId(project, zone, instance); + } + + /** + * Returns {@code true} if the provided string matches the expected format of an instance URL. + * Returns {@code false} otherwise. + */ + static boolean matchesUrl(String url) { + return PATTERN.matcher(url).matches(); + } + + static InstanceId fromUrl(String url) { + Matcher matcher = PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException(url + " is not a valid instance URL"); + } + return InstanceId.of(matcher.group(1), matcher.group(2), matcher.group(3)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java index 36d3037bc41b..0166e03ed325 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/LicenseId.java @@ -78,9 +78,14 @@ public int hashCode() { @Override public boolean equals(Object obj) { - return obj instanceof LicenseId - && baseEquals((LicenseId) obj) - && Objects.equals(license, ((LicenseId) obj).license); + if (obj == this) { + return true; + } + if (!(obj instanceof LicenseId)) { + return false; + } + LicenseId other = (LicenseId) obj; + return baseEquals(other) && Objects.equals(license, other.license); } @Override diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java index d9c446dddf72..2d7bfa7d26c8 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineType.java @@ -160,7 +160,7 @@ public MachineTypeId machineTypeId() { } /** - * Returns an unique identifier for the machine type; defined by the service. + * Returns the unique identifier for the machine type; defined by the service. */ public String id() { return id; diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java index 1252719e05d7..a431d29d1e85 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/MachineTypeId.java @@ -28,7 +28,7 @@ /** * Identity for a Google Compute Engine machine type. */ -public final class MachineTypeId extends ZoneResourceId { +public final class MachineTypeId extends ResourceId { static final Function FROM_URL_FUNCTION = new Function() { @@ -45,14 +45,16 @@ public String apply(MachineTypeId machineTypeId) { } }; - private static final String REGEX = ZoneResourceId.REGEX + "machineTypes/([^/]+)"; + private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/machineTypes/([^/]+)"; private static final Pattern PATTERN = Pattern.compile(REGEX); private static final long serialVersionUID = -5819598544478859608L; + private final String zone; private final String machineType; private MachineTypeId(String project, String zone, String machineType) { - super(project, zone); + super(project); + this.zone = checkNotNull(zone); this.machineType = checkNotNull(machineType); } @@ -63,26 +65,47 @@ public String machineType() { return machineType; } + /** + * Returns the name of the zone this machine type belongs to. + */ + public String zone() { + return zone; + } + + /** + * Returns the identity of the zone this machine type belongs to. + */ + public ZoneId zoneId() { + return ZoneId.of(project(), zone); + } + @Override public String selfLink() { - return super.selfLink() + "/machineTypes/" + machineType; + return super.selfLink() + "/zones/" + zone + "/machineTypes/" + machineType; } @Override MoreObjects.ToStringHelper toStringHelper() { - return super.toStringHelper().add("machineType", machineType); + return super.toStringHelper().add("zone", zone).add("machineType", machineType); } @Override public int hashCode() { - return Objects.hash(baseHashCode(), machineType); + return Objects.hash(baseHashCode(), zone, machineType); } @Override public boolean equals(Object obj) { - return obj instanceof MachineTypeId - && baseEquals((MachineTypeId) obj) - && Objects.equals(machineType, ((MachineTypeId) obj).machineType); + if (obj == this) { + return true; + } + if (!(obj instanceof MachineTypeId)) { + return false; + } + MachineTypeId other = (MachineTypeId) obj; + return baseEquals(other) + && Objects.equals(zone, other.zone) + && Objects.equals(machineType, other.machineType); } @Override @@ -90,7 +113,7 @@ MachineTypeId setProjectId(String projectId) { if (project() != null) { return this; } - return MachineTypeId.of(projectId, zone(), machineType); + return MachineTypeId.of(projectId, zone, machineType); } /** diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java index 7b8a888cf40c..ce519edc970d 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Operation.java @@ -17,8 +17,6 @@ package com.google.gcloud.compute; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.gcloud.compute.OperationId.Type.REGION; -import static com.google.gcloud.compute.OperationId.Type.ZONE; import com.google.common.base.Function; import com.google.common.base.MoreObjects; diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java index 7f9100aa61a2..5ddf2dae43a2 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/OperationId.java @@ -16,10 +16,25 @@ package com.google.gcloud.compute; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.MoreObjects; + +import java.util.Objects; + /** - * Interface for Google Compute Engine operation identities. + * Base class for Google Compute Engine operation identities. */ -public interface OperationId { +public abstract class OperationId extends ResourceId { + + private static final long serialVersionUID = -5502909279744388604L; + + private final String operation; + + OperationId(String project, String operation) { + super(project); + this.operation = checkNotNull(operation); + } /** * Possible types for a Google Compute Engine operation identity. @@ -30,11 +45,13 @@ enum Type { * addresses or snapshots. */ GLOBAL, + /** * Region operations are those operations that deal with resources that live in a region, such * as subnetworks. */ REGION, + /** * Zone operations are those operations that deal with resources that live in a zone, such as * disks and instances. @@ -45,20 +62,32 @@ enum Type { /** * Returns the type of this operation identity. */ - Type type(); - - /** - * Returns the name of the project. - */ - String project(); + public abstract Type type(); /** * Returns the name of the operation resource. */ - String operation(); + public String operation() { + return operation; + } - /** - * Returns a fully qualified URL to the operation. - */ - String selfLink(); + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("operation", operation); + } + + @Override + final int baseHashCode() { + return Objects.hash(super.baseHashCode(), operation); + } + + @Override + final boolean baseEquals(ResourceId resourceId) { + return resourceId instanceof OperationId + && super.baseEquals(resourceId) + && Objects.equals(operation, ((OperationId) resourceId).operation); + } + + @Override + abstract OperationId setProjectId(String projectId); } diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java index 470acf4e9061..fb7890187a14 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Region.java @@ -241,7 +241,7 @@ public RegionId regionId() { } /** - * Returns an unique identifier for the region; defined by the service. + * Returns the unique identifier for the region; defined by the service. */ public String id() { return id; diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionAddressId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionAddressId.java new file mode 100644 index 000000000000..6ea0538b0edf --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionAddressId.java @@ -0,0 +1,151 @@ +/* + * 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.gcloud.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.MoreObjects; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Identity for a Google Compute Engine region address. + */ +public final class RegionAddressId extends AddressId { + + private static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/addresses/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + private static final long serialVersionUID = 8170980880371085238L; + + private final String region; + + private RegionAddressId(String project, String region, String address) { + super(project, address); + this.region = checkNotNull(region); + } + + @Override + public Type type() { + return Type.REGION; + } + + /** + * Returns the name of the region this address belongs to. + */ + public String region() { + return region; + } + + /** + * Returns the identity of the region this address belongs to. + */ + public RegionId regionId() { + return RegionId.of(project(), region); + } + + @Override + public String selfLink() { + return super.selfLink() + "/regions/" + region + "/addresses/" + address(); + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("region", region); + } + + @Override + public int hashCode() { + return Objects.hash(baseHashCode(), region); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof RegionAddressId)) { + return false; + } + RegionAddressId other = (RegionAddressId) obj; + return baseEquals(other) && Objects.equals(region, other.region); + } + + @Override + RegionAddressId setProjectId(String projectId) { + if (project() != null) { + return this; + } + return RegionAddressId.of(projectId, region, address()); + } + + /** + * Returns a region address identity given the region identity and the address name. The address + * name must be 1-63 characters long, and comply with RFC1035. Specifically, the name must be 1-63 + * characters long and match the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means + * the first character must be a lowercase letter, and all following characters must be a dash, + * lowercase letter, or digit, except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static RegionAddressId of(RegionId regionId, String address) { + return new RegionAddressId(regionId.project(), regionId.region(), address); + } + + /** + * Returns a region address identity given the region and address names. The address name must be + * 1-63 characters long and comply with RFC1035. Specifically, the name must match the regular + * expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static RegionAddressId of(String region, String address) { + return new RegionAddressId(null, region, address); + } + + /** + * Returns a region address identity given project, region and address names. The address name + * must be 1-63 characters long and comply with RFC1035. Specifically, the name must match the + * regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must be a + * lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static RegionAddressId of(String project, String region, String address) { + return new RegionAddressId(project, region, address); + } + + /** + * Returns {@code true} if the provided string matches the expected format of a region address + * URL. Returns {@code false} otherwise. + */ + static boolean matchesUrl(String url) { + return PATTERN.matcher(url).matches(); + } + + static RegionAddressId fromUrl(String url) { + Matcher matcher = PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException(url + " is not a valid region address URL"); + } + return RegionAddressId.of(matcher.group(1), matcher.group(2), matcher.group(3)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionForwardingRuleId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionForwardingRuleId.java new file mode 100644 index 000000000000..b6e7e120f94a --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionForwardingRuleId.java @@ -0,0 +1,167 @@ +/* + * 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.gcloud.compute; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Function; +import com.google.common.base.MoreObjects; + +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Identity for a Google Compute Engine region's forwarding rule. + */ +public final class RegionForwardingRuleId extends ForwardingRuleId { + + static final Function FROM_URL_FUNCTION = + new Function() { + @Override + public RegionForwardingRuleId apply(String pb) { + return RegionForwardingRuleId.fromUrl(pb); + } + }; + static final Function TO_URL_FUNCTION = + new Function() { + @Override + public String apply(RegionForwardingRuleId forwardingRuleId) { + return forwardingRuleId.selfLink(); + } + }; + + private static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/forwardingRules/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + private static final long serialVersionUID = 7885327931402904667L; + + private final String region; + + private RegionForwardingRuleId(String project, String region, String rule) { + super(project, rule); + this.region = checkNotNull(region); + } + + @Override + public Type type() { + return Type.REGION; + } + + /** + * Returns the name of the region this forwarding rule belongs to. + */ + public String region() { + return region; + } + + /** + * Returns the identity of the region this forwarding rule belongs to. + */ + public RegionId regionId() { + return RegionId.of(project(), region); + } + + @Override + public String selfLink() { + return super.selfLink() + "/regions/" + region + "/forwardingRules/" + rule(); + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return MoreObjects.toStringHelper(this).add("region", region); + } + + @Override + public int hashCode() { + return Objects.hash(baseHashCode(), region); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof RegionForwardingRuleId)) { + return false; + } + RegionForwardingRuleId other = (RegionForwardingRuleId) obj; + return baseEquals(other) && Objects.equals(region, other.region); + } + + @Override + RegionForwardingRuleId setProjectId(String projectId) { + if (project() != null) { + return this; + } + return RegionForwardingRuleId.of(projectId, region, rule()); + } + + /** + * Returns a region forwarding rule identity given the region identity and the rule name. The + * forwarding rule name must be 1-63 characters long and comply with RFC1035. Specifically, the + * name must match the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first + * character must be a lowercase letter, and all following characters must be a dash, lowercase + * letter, or digit, except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static RegionForwardingRuleId of(RegionId regionId, String rule) { + return new RegionForwardingRuleId(regionId.project(), regionId.region(), rule); + } + + /** + * Returns a region forwarding rule identity given the region and rule names. The forwarding rule + * name must be 1-63 characters long and comply with RFC1035. Specifically, the name must match + * the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character must + * be a lowercase letter, and all following characters must be a dash, lowercase letter, or digit, + * except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static RegionForwardingRuleId of(String region, String rule) { + return new RegionForwardingRuleId(null, region, rule); + } + + /** + * Returns a region forwarding rule identity given project, region and rule names. The forwarding + * rule name must be 1-63 characters long and comply with RFC1035. Specifically, the name must + * match the regular expression {@code [a-z]([-a-z0-9]*[a-z0-9])?} which means the first character + * must be a lowercase letter, and all following characters must be a dash, lowercase letter, or + * digit, except the last character, which cannot be a dash. + * + * @see RFC1035 + */ + public static RegionForwardingRuleId of(String project, String region, String rule) { + return new RegionForwardingRuleId(project, region, rule); + } + + /** + * Returns {@code true} if the provided string matches the expected format of a region forwarding + * rule URL. Returns {@code false} otherwise. + */ + static boolean matchesUrl(String url) { + return PATTERN.matcher(url).matches(); + } + + static RegionForwardingRuleId fromUrl(String url) { + Matcher matcher = PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException(url + " is not a valid region forwarding rule URL"); + } + return RegionForwardingRuleId.of(matcher.group(1), matcher.group(2), matcher.group(3)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java index 403edd47ce48..7e0f03e1e3ac 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionId.java @@ -83,9 +83,14 @@ public int hashCode() { @Override public boolean equals(Object obj) { - return obj instanceof RegionId - && baseEquals((RegionId) obj) - && Objects.equals(region, ((RegionId) obj).region); + if (obj == this) { + return true; + } + if (!(obj instanceof RegionId)) { + return false; + } + RegionId other = (RegionId) obj; + return baseEquals(other) && Objects.equals(region, other.region); } @Override diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java index 96a772b5b9ea..b244c60fadf0 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionOperationId.java @@ -27,17 +27,17 @@ /** * Identity for a Google Compute Engine region's operation. */ -public final class RegionOperationId extends RegionResourceId implements OperationId { +public final class RegionOperationId extends OperationId { - private static final String REGEX = RegionResourceId.REGEX + "operations/([^/]+)"; + private static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/operations/([^/]+)"; private static final Pattern PATTERN = Pattern.compile(REGEX); private static final long serialVersionUID = 5816161906501886782L; - private final String operation; + private final String region; private RegionOperationId(String project, String region, String operation) { - super(project, region); - this.operation = checkNotNull(operation); + super(project, operation); + this.region = checkNotNull(region); } @Override @@ -45,31 +45,45 @@ public Type type() { return Type.REGION; } - @Override - public String operation() { - return operation; + /** + * Returns the name of the region this operation belongs to. + */ + public String region() { + return region; + } + + /** + * Returns the identity of the region this operation belongs to. + */ + public RegionId regionId() { + return RegionId.of(project(), region); } @Override public String selfLink() { - return super.selfLink() + "/operations/" + operation; + return super.selfLink() + "/regions/" + region + "/operations/" + operation(); } @Override MoreObjects.ToStringHelper toStringHelper() { - return MoreObjects.toStringHelper(this).add("operation", operation); + return MoreObjects.toStringHelper(this).add("region", region); } @Override public int hashCode() { - return Objects.hash(baseHashCode(), operation); + return Objects.hash(baseHashCode(), region); } @Override public boolean equals(Object obj) { - return obj instanceof RegionOperationId - && baseEquals((RegionOperationId) obj) - && Objects.equals(operation, ((RegionOperationId) obj).operation); + if (obj == this) { + return true; + } + if (!(obj instanceof RegionOperationId)) { + return false; + } + RegionOperationId other = (RegionOperationId) obj; + return baseEquals(other) && Objects.equals(region, other.region); } @Override @@ -77,7 +91,7 @@ RegionOperationId setProjectId(String projectId) { if (project() != null) { return this; } - return RegionOperationId.of(projectId, region(), operation); + return RegionOperationId.of(projectId, region, operation()); } /** diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionResourceId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionResourceId.java deleted file mode 100644 index eeb288b07be1..000000000000 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/RegionResourceId.java +++ /dev/null @@ -1,80 +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.gcloud.compute; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.MoreObjects.ToStringHelper; - -import java.util.Objects; - -/** - * A base class for the identity of Google Compute Engine resources that live in a region. - */ -public abstract class RegionResourceId extends ResourceId { - - static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/"; - private static final long serialVersionUID = 5569092266957249294L; - - private final String region; - - RegionResourceId(String project, String region) { - super(project); - this.region = checkNotNull(region); - } - - RegionResourceId(RegionId regionId) { - super(regionId.project()); - this.region = checkNotNull(regionId.region()); - } - - /** - * Returns the name of the region this resource belongs to. - */ - public final String region() { - return region; - } - - /** - * Returns the identity of the region this resource belongs to. - */ - public final RegionId regionId() { - return RegionId.of(project(), region); - } - - @Override - public String selfLink() { - return super.selfLink() + "/regions/" + region; - } - - @Override - ToStringHelper toStringHelper() { - return super.toStringHelper().add("region", region); - } - - @Override - final int baseHashCode() { - return Objects.hash(super.baseHashCode(), region); - } - - @Override - final boolean baseEquals(ResourceId resourceId) { - return resourceId instanceof RegionResourceId - && super.baseEquals(resourceId) - && Objects.equals(region, ((RegionResourceId) resourceId).region); - } -} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java index 903f994118de..7c766bef27c9 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/Zone.java @@ -270,7 +270,7 @@ public String description() { } /** - * Returns an unique identifier for the zone; defined by the service. + * Returns the unique identifier for the zone; defined by the service. */ public String id() { return id; diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java index 74ac5be58201..56386ace5455 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneId.java @@ -78,9 +78,14 @@ public int hashCode() { @Override public boolean equals(Object obj) { - return obj instanceof ZoneId - && baseEquals((ZoneId) obj) - && Objects.equals(zone, ((ZoneId) obj).zone); + if (obj == this) { + return true; + } + if (!(obj instanceof ZoneId)) { + return false; + } + ZoneId other = (ZoneId) obj; + return baseEquals(other) && Objects.equals(zone, other.zone); } @Override diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java index 837ca6888c83..99161b0f4eda 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneOperationId.java @@ -27,17 +27,17 @@ /** * Identity for a Google Compute Engine zone operation. */ -public final class ZoneOperationId extends ZoneResourceId implements OperationId { +public final class ZoneOperationId extends OperationId { - private static final String REGEX = ZoneResourceId.REGEX + "operations/([^/]+)"; + private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/operations/([^/]+)"; private static final Pattern PATTERN = Pattern.compile(REGEX); private static final long serialVersionUID = 4910670262094017392L; - private final String operation; + private final String zone; private ZoneOperationId(String project, String zone, String operation) { - super(project, zone); - this.operation = checkNotNull(operation); + super(project, operation); + this.zone = checkNotNull(zone); } @Override @@ -45,31 +45,40 @@ public Type type() { return Type.ZONE; } - @Override - public String operation() { - return operation; + /** + * Returns the name of the zone this operation belongs to. + */ + public String zone() { + return zone; + } + + /** + * Returns the identity of the zone this address belongs to. + */ + public ZoneId zoneId() { + return ZoneId.of(project(), zone); } @Override public String selfLink() { - return super.selfLink() + "/operations/" + operation; + return super.selfLink() + "/zones/" + zone + "/operations/" + operation(); } @Override MoreObjects.ToStringHelper toStringHelper() { - return MoreObjects.toStringHelper(this).add("operation", operation); + return MoreObjects.toStringHelper(this).add("zone", zone); } @Override public int hashCode() { - return Objects.hash(baseHashCode(), operation); + return Objects.hash(baseHashCode(), zone); } @Override public boolean equals(Object obj) { return obj instanceof ZoneOperationId && baseEquals((ZoneOperationId) obj) - && Objects.equals(operation, ((ZoneOperationId) obj).operation); + && Objects.equals(zone, ((ZoneOperationId) obj).zone); } @Override @@ -77,7 +86,7 @@ ZoneOperationId setProjectId(String projectId) { if (project() != null) { return this; } - return ZoneOperationId.of(projectId, zone(), operation); + return ZoneOperationId.of(projectId, zone, operation()); } /** diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneResourceId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneResourceId.java deleted file mode 100644 index 60117684c056..000000000000 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/ZoneResourceId.java +++ /dev/null @@ -1,80 +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.gcloud.compute; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.base.MoreObjects.ToStringHelper; - -import java.util.Objects; - -/** - * A base class for the identity of Google Compute Engine resources that live in a zone. - */ -public abstract class ZoneResourceId extends ResourceId { - - static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/"; - private static final long serialVersionUID = -6249546895344926888L; - - private final String zone; - - ZoneResourceId(String project, String zone) { - super(project); - this.zone = checkNotNull(zone); - } - - ZoneResourceId(ZoneId zoneId) { - super(zoneId.project()); - this.zone = checkNotNull(zoneId.zone()); - } - - /** - * Returns the name of the zone this resource belongs to. - */ - public final String zone() { - return zone; - } - - /** - * Returns the identity of the zone this resource belongs to. - */ - public final ZoneId zoneId() { - return ZoneId.of(project(), zone); - } - - @Override - public String selfLink() { - return super.selfLink() + "/zones/" + zone; - } - - @Override - ToStringHelper toStringHelper() { - return super.toStringHelper().add("zone", zone); - } - - @Override - final int baseHashCode() { - return Objects.hash(super.baseHashCode(), zone); - } - - @Override - final boolean baseEquals(ResourceId resourceId) { - return resourceId instanceof ZoneResourceId - && super.baseEquals(resourceId) - && Objects.equals(zone, ((ZoneResourceId) resourceId).zone); - } -} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java index 266b31cd7c93..3613c75a4b7c 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/testing/RemoteComputeHelper.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.io.InputStream; +import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; @@ -51,6 +52,16 @@ public ComputeOptions options() { return options; } + /** + * Returns a base name for testing resources generated using a random UUID. This base name can be + * prepended to resource names to prevent name clashes. This method always returns a 30 characters + * long prefix. Since Compute Engine resource names can be at most 63 characters long your suffix + * should be no longer than 33 characters. + */ + public static String baseResourceName() { + return "test-" + UUID.randomUUID().toString().replace("-", "").substring(0, 24) + "-"; + } + /** * Creates a {@code RemoteComputeHelper} object for the given project id and JSON key input * stream. @@ -60,8 +71,7 @@ public ComputeOptions options() { * @return A {@code RemoteComputeHelper} object for the provided options * @throws ComputeHelperException if {@code keyStream} is not a valid JSON key stream */ - public static RemoteComputeHelper create(String projectId, InputStream keyStream) - throws ComputeHelperException { + public static RemoteComputeHelper create(String projectId, InputStream keyStream) { try { ComputeOptions computeOptions = ComputeOptions.builder() .authCredentials(AuthCredentials.createForJson(keyStream)) diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java b/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java index 740ad73b5b2e..66152f5464a4 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/spi/ComputeRpc.java @@ -16,6 +16,7 @@ package com.google.gcloud.spi; +import com.google.api.services.compute.model.Address; import com.google.api.services.compute.model.DiskType; import com.google.api.services.compute.model.License; import com.google.api.services.compute.model.MachineType; @@ -228,4 +229,73 @@ public Y y() { * @throws ComputeException upon failure */ boolean deleteZoneOperation(String zone, String operation); + + /** + * Returns the requested global address or {@code null} if not found. + * + * @throws ComputeException upon failure + */ + Address getGlobalAddress(String address, Map options); + + /** + * Creates a new global address. + * + * @return a global operation for global address' creation + * @throws ComputeException upon failure + */ + Operation createGlobalAddress(Address address, Map options); + + /** + * Lists the global addresses. + * + * @throws ComputeException upon failure + */ + Tuple> listGlobalAddresses(Map options); + + /** + * Deletes the requested global address. + * + * @return a global operation if request was issued correctly, {@code null} if the address was not + * found + * @throws ComputeException upon failure + */ + Operation deleteGlobalAddress(String address, Map options); + + /** + * Returns the requested region address or {@code null} if not found. + * + * @throws ComputeException upon failure or if region is not found + */ + Address getRegionAddress(String region, String address, Map options); + + /** + * Creates a new region address. + * + * @return a region operation for region address' creation + * @throws ComputeException upon failure or if region is not found + */ + Operation createRegionAddress(String region, Address address, Map options); + + /** + * Lists the regions addresses for the provided region. + * + * @throws ComputeException upon failure or if region is not found + */ + Tuple> listRegionAddresses(String region, Map options); + + /** + * Lists all addresses. + * + * @throws ComputeException upon failure + */ + Tuple> listAddresses(Map options); + + /** + * Deletes the requested region address. + * + * @return a region operation if request was issued correctly, {@code null} if the address was not + * found + * @throws ComputeException upon failure or if region is not found + */ + Operation deleteRegionAddress(String region, String address, Map options); } diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/spi/DefaultComputeRpc.java b/gcloud-java-compute/src/main/java/com/google/gcloud/spi/DefaultComputeRpc.java index 3209084a5983..78100f1c3c1f 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/spi/DefaultComputeRpc.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/spi/DefaultComputeRpc.java @@ -26,6 +26,10 @@ import com.google.api.client.http.HttpTransport; import com.google.api.client.json.jackson.JacksonFactory; import com.google.api.services.compute.Compute; +import com.google.api.services.compute.model.Address; +import com.google.api.services.compute.model.AddressAggregatedList; +import com.google.api.services.compute.model.AddressList; +import com.google.api.services.compute.model.AddressesScopedList; import com.google.api.services.compute.model.DiskType; import com.google.api.services.compute.model.DiskTypeAggregatedList; import com.google.api.services.compute.model.DiskTypeList; @@ -285,7 +289,7 @@ public boolean deleteGlobalOperation(String operation) { compute.globalOperations().delete(this.options.projectId(), operation).execute(); return true; } catch (IOException ex) { - return nullForNotFound(ex); + return falseForNotFound(ex); } } @@ -325,7 +329,7 @@ public boolean deleteRegionOperation(String region, String operation) { compute.regionOperations().delete(this.options.projectId(), region, operation).execute(); return true; } catch (IOException ex) { - return nullForNotFound(ex); + return falseForNotFound(ex); } } @@ -364,6 +368,140 @@ public boolean deleteZoneOperation(String zone, String operation) { try { compute.zoneOperations().delete(this.options.projectId(), zone, operation).execute(); return true; + } catch (IOException ex) { + return falseForNotFound(ex); + } + } + + @Override + public Address getGlobalAddress(String address, Map options) { + try { + return compute.globalAddresses() + .get(this.options.projectId(), address) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation createGlobalAddress(Address address, Map options) { + try { + return compute.globalAddresses() + .insert(this.options.projectId(), address) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Tuple> listGlobalAddresses(Map options) { + try { + AddressList addressList = compute.globalAddresses() + .list(this.options.projectId()) + .setFilter(FILTER.getString(options)) + .setMaxResults(MAX_RESULTS.getLong(options)) + .setPageToken(PAGE_TOKEN.getString(options)) + .setFields(FIELDS.getString(options)) + .execute(); + Iterable
operations = addressList.getItems(); + return Tuple.of(addressList.getNextPageToken(), operations); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Operation deleteGlobalAddress(String address, Map options) { + try { + return compute.globalAddresses() + .delete(this.options.projectId(), address) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Address getRegionAddress(String region, String address, Map options) { + try { + return compute.addresses() + .get(this.options.projectId(), region, address) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + return nullForNotFound(ex); + } + } + + @Override + public Operation createRegionAddress(String region, Address address, Map options) { + try { + return compute.addresses() + .insert(this.options.projectId(), region, address) + .setFields(FIELDS.getString(options)) + .execute(); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Tuple> listRegionAddresses(String region, + Map options) { + try { + AddressList addressList = compute.addresses() + .list(this.options.projectId(), region) + .setFilter(FILTER.getString(options)) + .setMaxResults(MAX_RESULTS.getLong(options)) + .setPageToken(PAGE_TOKEN.getString(options)) + .setFields(FIELDS.getString(options)) + .execute(); + Iterable
operations = addressList.getItems(); + return Tuple.of(addressList.getNextPageToken(), operations); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Tuple> listAddresses(Map options) { + try { + AddressAggregatedList aggregatedList = compute.addresses() + .aggregatedList(this.options.projectId()) + .setFilter(FILTER.getString(options)) + .setMaxResults(MAX_RESULTS.getLong(options)) + .setPageToken(PAGE_TOKEN.getString(options)) + // todo(mziccard): uncomment or remove once #711 is closed + // .setFields(FIELDS.getString(options)) + .execute(); + ImmutableList.Builder
builder = ImmutableList.builder(); + Map scopedList = aggregatedList.getItems(); + if (scopedList != null) { + for (AddressesScopedList addressesScopedList : scopedList.values()) { + if (addressesScopedList.getAddresses() != null) { + builder.addAll(addressesScopedList.getAddresses()); + } + } + } + return Tuple.>of(aggregatedList.getNextPageToken(), + builder.build()); + } catch (IOException ex) { + throw translate(ex); + } + } + + @Override + public Operation deleteRegionAddress(String region, String address, Map options) { + try { + return compute.addresses() + .delete(this.options.projectId(), region, address) + .setFields(FIELDS.getString(options)) + .execute(); } catch (IOException ex) { return nullForNotFound(ex); } @@ -382,4 +520,18 @@ private static T nullForNotFound(IOException exception) { } throw serviceException; } + + /** + * This method returns {@code false} if the error code of {@code exception} was 404, re-throws the + * exception otherwise. + * + * @throws ComputeException if the error code of {@code exception} was not 404 + */ + private static boolean falseForNotFound(IOException exception) { + ComputeException serviceException = translate(exception); + if (serviceException.code() == HTTP_NOT_FOUND) { + return false; + } + throw serviceException; + } } diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressIdTest.java new file mode 100644 index 000000000000..804744af5615 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressIdTest.java @@ -0,0 +1,119 @@ +/* + * 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.gcloud.compute; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class AddressIdTest { + + private static final String PROJECT = "project"; + private static final String REGION = "region"; + private static final String NAME = "addr"; + private static final String GLOBAL_URL = + "https://www.googleapis.com/compute/v1/projects/project/global/addresses/addr"; + private static final String REGION_URL = + "https://www.googleapis.com/compute/v1/projects/project/regions/region/addresses/addr"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testOf() { + GlobalAddressId addressId = GlobalAddressId.of(PROJECT, NAME); + assertEquals(PROJECT, addressId.project()); + assertEquals(NAME, addressId.address()); + assertEquals(GLOBAL_URL, addressId.selfLink()); + addressId = GlobalAddressId.of(NAME); + assertNull(addressId.project()); + assertEquals(NAME, addressId.address()); + RegionAddressId regionAddressId = RegionAddressId.of(PROJECT, REGION, NAME); + assertEquals(PROJECT, regionAddressId.project()); + assertEquals(REGION, regionAddressId.region()); + assertEquals(NAME, regionAddressId.address()); + assertEquals(REGION_URL, regionAddressId.selfLink()); + regionAddressId = RegionAddressId.of(RegionId.of(PROJECT, REGION), NAME); + assertEquals(PROJECT, regionAddressId.project()); + assertEquals(REGION, regionAddressId.region()); + assertEquals(NAME, regionAddressId.address()); + assertEquals(REGION_URL, regionAddressId.selfLink()); + regionAddressId = RegionAddressId.of(REGION, NAME); + assertNull(regionAddressId.project()); + assertEquals(REGION, regionAddressId.region()); + assertEquals(NAME, regionAddressId.address()); + } + + @Test + public void testToAndFromUrlGlobal() { + GlobalAddressId addressId = GlobalAddressId.of(PROJECT, NAME); + compareAddressId(addressId, GlobalAddressId.fromUrl(addressId.selfLink())); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("notMatchingUrl is not a valid global address URL"); + GlobalAddressId.fromUrl("notMatchingUrl"); + } + + @Test + public void testToAndFromUrlRegion() { + RegionAddressId regionAddressId = RegionAddressId.of(PROJECT, REGION, NAME); + compareRegionAddressId(regionAddressId, RegionAddressId.fromUrl(regionAddressId.selfLink())); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("notMatchingUrl is not a valid region address URL"); + RegionAddressId.fromUrl("notMatchingUrl"); + } + + @Test + public void testSetProjectId() { + GlobalAddressId addressId = GlobalAddressId.of(PROJECT, NAME); + assertSame(addressId, addressId.setProjectId(PROJECT)); + compareAddressId(addressId, GlobalAddressId.of(NAME).setProjectId(PROJECT)); + RegionAddressId regionAddressId = RegionAddressId.of(PROJECT, REGION, NAME); + assertSame(regionAddressId, regionAddressId.setProjectId(PROJECT)); + compareRegionAddressId(regionAddressId, RegionAddressId.of(REGION, NAME).setProjectId(PROJECT)); + } + + @Test + public void testMatchesUrl() { + assertTrue(GlobalAddressId.matchesUrl(GlobalAddressId.of(PROJECT, NAME).selfLink())); + assertFalse(GlobalAddressId.matchesUrl("notMatchingUrl")); + assertTrue(RegionAddressId.matchesUrl(RegionAddressId.of(PROJECT, REGION, NAME).selfLink())); + assertFalse(RegionAddressId.matchesUrl("notMatchingUrl")); + } + + private void compareAddressId(GlobalAddressId expected, GlobalAddressId value) { + assertEquals(expected, value); + assertEquals(expected.project(), expected.project()); + assertEquals(expected.address(), expected.address()); + assertEquals(expected.selfLink(), expected.selfLink()); + assertEquals(expected.hashCode(), expected.hashCode()); + } + + private void compareRegionAddressId(RegionAddressId expected, RegionAddressId value) { + assertEquals(expected, value); + assertEquals(expected.project(), expected.project()); + assertEquals(expected.region(), expected.region()); + assertEquals(expected.address(), expected.address()); + assertEquals(expected.selfLink(), expected.selfLink()); + assertEquals(expected.hashCode(), expected.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressInfoTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressInfoTest.java new file mode 100644 index 000000000000..cb4ba3678c30 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressInfoTest.java @@ -0,0 +1,201 @@ +/* + * 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.gcloud.compute; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import com.google.common.collect.ImmutableList; +import com.google.gcloud.compute.AddressInfo.GlobalForwardingUsage; +import com.google.gcloud.compute.AddressInfo.InstanceUsage; +import com.google.gcloud.compute.AddressInfo.RegionForwardingUsage; + +import org.junit.Test; + +import java.util.List; + +public class AddressInfoTest { + + private static final String ADDRESS = "192.168.1.1"; + private static final Long CREATION_TIMESTAMP = 1452602400000L; + private static final String DESCRIPTION = "description"; + private static final String ID = "42"; + private static final GlobalAddressId GLOBAL_ADDRESS_ID = GlobalAddressId.of("project", "address"); + private static final RegionAddressId REGION_ADDRESS_ID = + RegionAddressId.of("project", "region", "address"); + private static final AddressInfo.Status STATUS = AddressInfo.Status.RESERVED; + private static final List GLOBAL_FORWARDING_RULES = + ImmutableList.of(GlobalForwardingRuleId.of("project", "forwardingRule1"), + GlobalForwardingRuleId.of("project", "forwardingRule2")); + private static final List REGION_FORWARDING_RULES = + ImmutableList.of(RegionForwardingRuleId.of("project", "region", "forwardingRule1"), + RegionForwardingRuleId.of("project", "region", "forwardingRule2")); + private static final InstanceUsage INSTANCE_USAGE = + new InstanceUsage(InstanceId.of("project", "zone", "instance1")); + private static final GlobalForwardingUsage GLOBAL_FORWARDING_USAGE = + new GlobalForwardingUsage(GLOBAL_FORWARDING_RULES); + private static final RegionForwardingUsage REGION_FORWARDING_USAGE = + new RegionForwardingUsage(REGION_FORWARDING_RULES); + private static final AddressInfo INSTANCE_ADDRESS_INFO = AddressInfo.builder(REGION_ADDRESS_ID) + .address(ADDRESS) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .status(STATUS) + .usage(INSTANCE_USAGE) + .build(); + private static final AddressInfo GLOBAL_FORWARDING_ADDRESS_INFO = + AddressInfo.builder(GLOBAL_ADDRESS_ID) + .address(ADDRESS) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .status(STATUS) + .usage(GLOBAL_FORWARDING_USAGE) + .build(); + private static final AddressInfo REGION_FORWARDING_ADDRESS_INFO = + AddressInfo.builder(REGION_ADDRESS_ID) + .address(ADDRESS) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .status(STATUS) + .usage(REGION_FORWARDING_USAGE) + .build(); + + @Test + public void testToBuilder() { + compareAddressInfo(INSTANCE_ADDRESS_INFO, INSTANCE_ADDRESS_INFO.toBuilder().build()); + AddressInfo addressInfo = INSTANCE_ADDRESS_INFO.toBuilder() + .address("192.168.1.2") + .description("description2") + .build(); + assertEquals("description2", addressInfo.description()); + assertEquals("192.168.1.2", addressInfo.address()); + addressInfo = addressInfo.toBuilder() + .address("192.168.1.1") + .description("description") + .build(); + compareAddressInfo(INSTANCE_ADDRESS_INFO, addressInfo); + } + + @Test + public void testToBuilderIncomplete() { + AddressInfo addressInfo = AddressInfo.builder(GLOBAL_ADDRESS_ID).build(); + assertEquals(addressInfo, addressInfo.toBuilder().build()); + addressInfo = AddressInfo.builder(REGION_ADDRESS_ID).build(); + assertEquals(addressInfo, addressInfo.toBuilder().build()); + } + + @Test + public void testBuilder() { + assertEquals(ADDRESS, INSTANCE_ADDRESS_INFO.address()); + assertEquals(CREATION_TIMESTAMP, INSTANCE_ADDRESS_INFO.creationTimestamp()); + assertEquals(DESCRIPTION, INSTANCE_ADDRESS_INFO.description()); + assertEquals(ID, INSTANCE_ADDRESS_INFO.id()); + assertEquals(REGION_ADDRESS_ID, INSTANCE_ADDRESS_INFO.addressId()); + assertEquals(STATUS, INSTANCE_ADDRESS_INFO.status()); + assertEquals(INSTANCE_USAGE, INSTANCE_ADDRESS_INFO.usage()); + assertEquals(INSTANCE_USAGE.instance(), + INSTANCE_ADDRESS_INFO.usage().instance()); + assertEquals(ADDRESS, REGION_FORWARDING_ADDRESS_INFO.address()); + assertEquals(CREATION_TIMESTAMP, REGION_FORWARDING_ADDRESS_INFO.creationTimestamp()); + assertEquals(DESCRIPTION, REGION_FORWARDING_ADDRESS_INFO.description()); + assertEquals(ID, REGION_FORWARDING_ADDRESS_INFO.id()); + assertEquals(REGION_ADDRESS_ID, REGION_FORWARDING_ADDRESS_INFO.addressId()); + assertEquals(STATUS, REGION_FORWARDING_ADDRESS_INFO.status()); + assertEquals(REGION_FORWARDING_USAGE, REGION_FORWARDING_ADDRESS_INFO.usage()); + assertEquals(REGION_FORWARDING_RULES, + REGION_FORWARDING_ADDRESS_INFO.usage().forwardingRules()); + assertEquals(ADDRESS, GLOBAL_FORWARDING_ADDRESS_INFO.address()); + assertEquals(CREATION_TIMESTAMP, GLOBAL_FORWARDING_ADDRESS_INFO.creationTimestamp()); + assertEquals(DESCRIPTION, GLOBAL_FORWARDING_ADDRESS_INFO.description()); + assertEquals(ID, GLOBAL_FORWARDING_ADDRESS_INFO.id()); + assertEquals(GLOBAL_ADDRESS_ID, GLOBAL_FORWARDING_ADDRESS_INFO.addressId()); + assertEquals(STATUS, GLOBAL_FORWARDING_ADDRESS_INFO.status()); + assertEquals(GLOBAL_FORWARDING_USAGE, GLOBAL_FORWARDING_ADDRESS_INFO.usage()); + assertEquals(GLOBAL_FORWARDING_RULES, + GLOBAL_FORWARDING_ADDRESS_INFO.usage().forwardingRules()); + } + + @Test + public void testOf() { + AddressInfo addressInfo = AddressInfo.of("address"); + assertEquals(GlobalAddressId.of("address"), addressInfo.addressId()); + assertNull(addressInfo.address()); + assertNull(addressInfo.creationTimestamp()); + assertNull(addressInfo.description()); + assertNull(addressInfo.id()); + assertNull(addressInfo.status()); + assertNull(addressInfo.usage()); + addressInfo = AddressInfo.of(GLOBAL_ADDRESS_ID); + assertEquals(GLOBAL_ADDRESS_ID, addressInfo.addressId()); + assertNull(addressInfo.address()); + assertNull(addressInfo.creationTimestamp()); + assertNull(addressInfo.description()); + assertNull(addressInfo.id()); + assertNull(addressInfo.status()); + assertNull(addressInfo.usage()); + addressInfo = AddressInfo.of("region", "address"); + assertEquals(RegionAddressId.of("region", "address"), addressInfo.addressId()); + assertNull(addressInfo.address()); + assertNull(addressInfo.creationTimestamp()); + assertNull(addressInfo.description()); + assertNull(addressInfo.id()); + assertNull(addressInfo.status()); + assertNull(addressInfo.usage()); + addressInfo = AddressInfo.of(RegionId.of("region"), "address"); + assertEquals(RegionAddressId.of("region", "address"), addressInfo.addressId()); + assertNull(addressInfo.address()); + assertNull(addressInfo.creationTimestamp()); + assertNull(addressInfo.description()); + assertNull(addressInfo.id()); + assertNull(addressInfo.status()); + assertNull(addressInfo.usage()); + } + + @Test + public void testToPbAndFromPb() { + compareAddressInfo(INSTANCE_ADDRESS_INFO, AddressInfo.fromPb(INSTANCE_ADDRESS_INFO.toPb())); + compareAddressInfo(REGION_FORWARDING_ADDRESS_INFO, + AddressInfo.fromPb(REGION_FORWARDING_ADDRESS_INFO.toPb())); + compareAddressInfo(GLOBAL_FORWARDING_ADDRESS_INFO, + AddressInfo.fromPb(GLOBAL_FORWARDING_ADDRESS_INFO.toPb())); + AddressInfo addressInfo = AddressInfo.builder(GLOBAL_ADDRESS_ID).build(); + compareAddressInfo(addressInfo, AddressInfo.fromPb(addressInfo.toPb())); + } + + @Test + public void testSetProjectId() { + AddressInfo addressInfo = GLOBAL_FORWARDING_ADDRESS_INFO.toBuilder() + .addressId(GlobalAddressId.of(GLOBAL_ADDRESS_ID.address())) + .build(); + compareAddressInfo(GLOBAL_FORWARDING_ADDRESS_INFO, addressInfo.setProjectId("project")); + } + + private void compareAddressInfo(AddressInfo expected, AddressInfo value) { + assertEquals(expected, value); + assertEquals(expected.address(), value.address()); + assertEquals(expected.creationTimestamp(), value.creationTimestamp()); + assertEquals(expected.description(), value.description()); + assertEquals(expected.id(), value.id()); + assertEquals(expected.addressId(), value.addressId()); + assertEquals(expected.usage(), value.usage()); + assertEquals(expected.status(), value.status()); + assertEquals(expected.hashCode(), value.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressTest.java new file mode 100644 index 000000000000..230f603271f9 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/AddressTest.java @@ -0,0 +1,294 @@ +/* + * 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.gcloud.compute; + +import static org.easymock.EasyMock.createMock; +import static org.easymock.EasyMock.createStrictMock; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.replay; +import static org.easymock.EasyMock.verify; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.ImmutableList; + +import org.junit.After; +import org.junit.Test; + +import java.util.List; + +public class AddressTest { + + private static final String ADDRESS = "192.168.1.1"; + private static final Long CREATION_TIMESTAMP = 1452602400000L; + private static final String DESCRIPTION = "description"; + private static final String ID = "42"; + private static final GlobalAddressId GLOBAL_ADDRESS_ID = GlobalAddressId.of("project", "address"); + private static final RegionAddressId REGION_ADDRESS_ID = + RegionAddressId.of("project", "region", "address"); + private static final AddressInfo.Status STATUS = AddressInfo.Status.RESERVED; + private static final List GLOBAL_FORWARDING_RULES = + ImmutableList.of(GlobalForwardingRuleId.of("project", "forwardingRule1"), + GlobalForwardingRuleId.of("project", "forwardingRule2")); + private static final List REGION_FORWARDING_RULES = + ImmutableList.of(RegionForwardingRuleId.of("project", "region", "forwardingRule1"), + RegionForwardingRuleId.of("project", "region", "forwardingRule2")); + private static final AddressInfo.InstanceUsage INSTANCE_USAGE = + new AddressInfo.InstanceUsage(InstanceId.of("project", "zone", "instance1")); + private static final AddressInfo.GlobalForwardingUsage GLOBAL_FORWARDING_USAGE = + new AddressInfo.GlobalForwardingUsage(GLOBAL_FORWARDING_RULES); + private static final AddressInfo.RegionForwardingUsage REGION_FORWARDING_USAGE = + new AddressInfo.RegionForwardingUsage(REGION_FORWARDING_RULES); + + private Compute serviceMockReturnsOptions = createStrictMock(Compute.class); + private ComputeOptions mockOptions = createMock(ComputeOptions.class); + private Compute compute; + private Address globalForwardingAddress; + private Address instanceAddress; + private Address regionForwardingAddress; + private Address address; + + private void initializeExpectedAddress(int optionsCalls) { + expect(serviceMockReturnsOptions.options()).andReturn(mockOptions).times(optionsCalls); + replay(serviceMockReturnsOptions); + instanceAddress = new Address.Builder(serviceMockReturnsOptions, REGION_ADDRESS_ID) + .address(ADDRESS) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .status(STATUS) + .usage(INSTANCE_USAGE) + .build(); + globalForwardingAddress = new Address.Builder(serviceMockReturnsOptions, GLOBAL_ADDRESS_ID) + .address(ADDRESS) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .status(STATUS) + .usage(GLOBAL_FORWARDING_USAGE) + .build(); + regionForwardingAddress = new Address.Builder(serviceMockReturnsOptions, REGION_ADDRESS_ID) + .address(ADDRESS) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .status(STATUS) + .usage(REGION_FORWARDING_USAGE) + .build(); + compute = createStrictMock(Compute.class); + } + + private void initializeAddress() { + address = new Address.Builder(compute, REGION_ADDRESS_ID) + .address(ADDRESS) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .status(STATUS) + .usage(REGION_FORWARDING_USAGE) + .build(); + } + + @After + public void tearDown() throws Exception { + verify(serviceMockReturnsOptions); + } + + @Test + public void testBuilder() { + initializeExpectedAddress(6); + assertEquals(ADDRESS, instanceAddress.address()); + assertEquals(CREATION_TIMESTAMP, instanceAddress.creationTimestamp()); + assertEquals(DESCRIPTION, instanceAddress.description()); + assertEquals(ID, instanceAddress.id()); + assertEquals(REGION_ADDRESS_ID, instanceAddress.addressId()); + assertEquals(STATUS, instanceAddress.status()); + assertEquals(INSTANCE_USAGE, instanceAddress.usage()); + assertSame(serviceMockReturnsOptions, instanceAddress.compute()); + assertEquals(ADDRESS, regionForwardingAddress.address()); + assertEquals(CREATION_TIMESTAMP, regionForwardingAddress.creationTimestamp()); + assertEquals(DESCRIPTION, regionForwardingAddress.description()); + assertEquals(ID, regionForwardingAddress.id()); + assertEquals(REGION_ADDRESS_ID, regionForwardingAddress.addressId()); + assertEquals(STATUS, regionForwardingAddress.status()); + assertEquals(REGION_FORWARDING_USAGE, regionForwardingAddress.usage()); + assertSame(serviceMockReturnsOptions, regionForwardingAddress.compute()); + assertEquals(ADDRESS, globalForwardingAddress.address()); + assertEquals(CREATION_TIMESTAMP, globalForwardingAddress.creationTimestamp()); + assertEquals(DESCRIPTION, globalForwardingAddress.description()); + assertEquals(ID, globalForwardingAddress.id()); + assertEquals(GLOBAL_ADDRESS_ID, globalForwardingAddress.addressId()); + assertEquals(STATUS, globalForwardingAddress.status()); + assertEquals(GLOBAL_FORWARDING_USAGE, globalForwardingAddress.usage()); + assertSame(serviceMockReturnsOptions, globalForwardingAddress.compute()); + Address address = new Address.Builder(serviceMockReturnsOptions, GLOBAL_ADDRESS_ID).build(); + assertEquals(GLOBAL_ADDRESS_ID, address.addressId()); + assertSame(serviceMockReturnsOptions, address.compute()); + assertNull(address.address()); + assertNull(address.creationTimestamp()); + assertNull(address.description()); + assertNull(address.id()); + assertNull(address.status()); + assertNull(address.usage()); + address = new Address.Builder(serviceMockReturnsOptions, REGION_ADDRESS_ID).build(); + assertEquals(REGION_ADDRESS_ID, address.addressId()); + assertSame(serviceMockReturnsOptions, address.compute()); + assertNull(address.address()); + assertNull(address.creationTimestamp()); + assertNull(address.description()); + assertNull(address.id()); + assertNull(address.status()); + assertNull(address.usage()); + address = new Address.Builder(serviceMockReturnsOptions, REGION_ADDRESS_ID) + .addressId(GLOBAL_ADDRESS_ID) + .build(); + assertEquals(GLOBAL_ADDRESS_ID, address.addressId()); + assertSame(serviceMockReturnsOptions, address.compute()); + assertNull(address.address()); + assertNull(address.creationTimestamp()); + assertNull(address.description()); + assertNull(address.id()); + assertNull(address.status()); + assertNull(address.usage()); + } + + @Test + public void testToBuilder() { + initializeExpectedAddress(16); + compareAddress(instanceAddress, instanceAddress.toBuilder().build()); + compareAddress(globalForwardingAddress, globalForwardingAddress.toBuilder().build()); + compareAddress(regionForwardingAddress, regionForwardingAddress.toBuilder().build()); + Address newAddress = instanceAddress.toBuilder().description("newDescription").build(); + assertEquals("newDescription", newAddress.description()); + newAddress = newAddress.toBuilder().description("description").build(); + compareAddress(instanceAddress, newAddress); + } + + @Test + public void testToAndFromPb() { + initializeExpectedAddress(20); + compareAddress(globalForwardingAddress, + Address.fromPb(serviceMockReturnsOptions, globalForwardingAddress.toPb())); + compareAddress(regionForwardingAddress, + Address.fromPb(serviceMockReturnsOptions, regionForwardingAddress.toPb())); + compareAddress(instanceAddress, + Address.fromPb(serviceMockReturnsOptions, instanceAddress.toPb())); + Address address = new Address.Builder(serviceMockReturnsOptions, GLOBAL_ADDRESS_ID).build(); + compareAddress(address, Address.fromPb(serviceMockReturnsOptions, address.toPb())); + address = new Address.Builder(serviceMockReturnsOptions, REGION_ADDRESS_ID).build(); + compareAddress(address, Address.fromPb(serviceMockReturnsOptions, address.toPb())); + } + + @Test + public void testDeleteOperation() { + initializeExpectedAddress(4); + expect(compute.options()).andReturn(mockOptions); + Operation operation = new Operation.Builder(serviceMockReturnsOptions) + .operationId(GlobalOperationId.of("project", "op")) + .build(); + expect(compute.delete(REGION_ADDRESS_ID)).andReturn(operation); + replay(compute); + initializeAddress(); + assertSame(operation, address.delete()); + } + + @Test + public void testDeleteNull() { + initializeExpectedAddress(3); + expect(compute.options()).andReturn(mockOptions); + expect(compute.delete(REGION_ADDRESS_ID)).andReturn(null); + replay(compute); + initializeAddress(); + assertNull(address.delete()); + } + + @Test + public void testExists_True() throws Exception { + initializeExpectedAddress(3); + Compute.AddressOption[] expectedOptions = {Compute.AddressOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(REGION_ADDRESS_ID, expectedOptions)).andReturn(regionForwardingAddress); + replay(compute); + initializeAddress(); + assertTrue(address.exists()); + verify(compute); + } + + @Test + public void testExists_False() throws Exception { + initializeExpectedAddress(3); + Compute.AddressOption[] expectedOptions = {Compute.AddressOption.fields()}; + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(REGION_ADDRESS_ID, expectedOptions)).andReturn(null); + replay(compute); + initializeAddress(); + assertFalse(address.exists()); + verify(compute); + } + + @Test + public void testReload() throws Exception { + initializeExpectedAddress(5); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(REGION_ADDRESS_ID)).andReturn(regionForwardingAddress); + replay(compute); + initializeAddress(); + Address updatedAddress = address.reload(); + compareAddress(regionForwardingAddress, updatedAddress); + verify(compute); + } + + @Test + public void testReloadNull() throws Exception { + initializeExpectedAddress(3); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(REGION_ADDRESS_ID)).andReturn(null); + replay(compute); + initializeAddress(); + assertNull(address.reload()); + verify(compute); + } + + @Test + public void testReloadWithOptions() throws Exception { + initializeExpectedAddress(5); + expect(compute.options()).andReturn(mockOptions); + expect(compute.get(REGION_ADDRESS_ID, Compute.AddressOption.fields())) + .andReturn(regionForwardingAddress); + replay(compute); + initializeAddress(); + Address updatedAddress = address.reload(Compute.AddressOption.fields()); + compareAddress(regionForwardingAddress, updatedAddress); + verify(compute); + } + + private void compareAddress(Address expected, Address value) { + assertEquals(expected, value); + assertEquals(expected.compute().options(), value.compute().options()); + assertEquals(expected.address(), value.address()); + assertEquals(expected.creationTimestamp(), value.creationTimestamp()); + assertEquals(expected.description(), value.description()); + assertEquals(expected.id(), value.id()); + assertEquals(expected.addressId(), value.addressId()); + assertEquals(expected.usage(), value.usage()); + assertEquals(expected.status(), value.status()); + assertEquals(expected.hashCode(), value.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java index e1a81b5afe48..808d4ce7d255 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ComputeImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Google Inc. All Rights Reserved. + * 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. @@ -174,6 +174,12 @@ public class ComputeImplTest { ZoneOperationId.of("project", "zone", "op"); private static final RegionOperationId REGION_OPERATION_ID = RegionOperationId.of("project", "region", "op"); + private static final RegionAddressId REGION_ADDRESS_ID = + RegionAddressId.of("project", "region", "address"); + private static final GlobalAddressId GLOBAL_ADDRESS_ID = + GlobalAddressId.of("project", "address"); + private static final AddressInfo REGION_ADDRESS = AddressInfo.builder(REGION_ADDRESS_ID).build(); + private static final AddressInfo GLOBAL_ADDRESS = AddressInfo.builder(GLOBAL_ADDRESS_ID).build(); // Empty ComputeRpc options private static final Map EMPTY_RPC_OPTIONS = ImmutableMap.of(); @@ -186,8 +192,8 @@ public class ComputeImplTest { private static final DiskTypeFilter DISK_TYPE_FILTER = DiskTypeFilter.equals(Compute.DiskTypeField.DESCRIPTION, "someDescription"); private static final DiskTypeListOption DISK_TYPE_LIST_PAGE_TOKEN = - DiskTypeListOption.startPageToken("cursor"); - private static final DiskTypeListOption DISK_TYPE_LIST_MAX_RESULTS = + DiskTypeListOption.pageToken("cursor"); + private static final DiskTypeListOption DISK_TYPE_LIST_PAGE_SIZE = DiskTypeListOption.pageSize(42L); private static final DiskTypeListOption DISK_TYPE_LIST_FILTER = DiskTypeListOption.filter(DISK_TYPE_FILTER); @@ -198,8 +204,8 @@ public class ComputeImplTest { // DiskType aggregated list options private static final DiskTypeAggregatedListOption DISK_TYPE_AGGREGATED_LIST_PAGE_TOKEN = - DiskTypeAggregatedListOption.startPageToken("cursor"); - private static final DiskTypeAggregatedListOption DISK_TYPE_AGGREGATED_LIST_MAX_RESULTS = + DiskTypeAggregatedListOption.pageToken("cursor"); + private static final DiskTypeAggregatedListOption DISK_TYPE_AGGREGATED_LIST_PAGE_SIZE = DiskTypeAggregatedListOption.pageSize(42L); private static final DiskTypeAggregatedListOption DISK_TYPE_AGGREGATED_LIST_FILTER = DiskTypeAggregatedListOption.filter(DISK_TYPE_FILTER); @@ -213,8 +219,8 @@ public class ComputeImplTest { private static final MachineTypeFilter MACHINE_TYPE_FILTER = MachineTypeFilter.notEquals(Compute.MachineTypeField.MAXIMUM_PERSISTENT_DISKS, 42L); private static final MachineTypeListOption MACHINE_TYPE_LIST_PAGE_TOKEN = - MachineTypeListOption.startPageToken("cursor"); - private static final MachineTypeListOption MACHINE_TYPE_LIST_MAX_RESULTS = + MachineTypeListOption.pageToken("cursor"); + private static final MachineTypeListOption MACHINE_TYPE_LIST_PAGE_SIZE = MachineTypeListOption.pageSize(42L); private static final MachineTypeListOption MACHINE_TYPE_LIST_FILTER = MachineTypeListOption.filter(MACHINE_TYPE_FILTER); @@ -225,8 +231,8 @@ public class ComputeImplTest { // MachineType aggregated list options private static final MachineTypeAggregatedListOption MACHINE_TYPE_AGGREGATED_LIST_PAGE_TOKEN = - MachineTypeAggregatedListOption.startPageToken("cursor"); - private static final MachineTypeAggregatedListOption MACHINE_TYPE_AGGREGATED_LIST_MAX_RESULTS = + MachineTypeAggregatedListOption.pageToken("cursor"); + private static final MachineTypeAggregatedListOption MACHINE_TYPE_AGGREGATED_LIST_PAGE_SIZE = MachineTypeAggregatedListOption.pageSize(42L); private static final MachineTypeAggregatedListOption MACHINE_TYPE_AGGREGATED_LIST_FILTER = MachineTypeAggregatedListOption.filter(MACHINE_TYPE_FILTER); @@ -239,8 +245,8 @@ public class ComputeImplTest { private static final RegionFilter REGION_FILTER = RegionFilter.equals(Compute.RegionField.ID, "someId"); private static final RegionListOption REGION_LIST_PAGE_TOKEN = - RegionListOption.startPageToken("cursor"); - private static final RegionListOption REGION_LIST_MAX_RESULTS = + RegionListOption.pageToken("cursor"); + private static final RegionListOption REGION_LIST_PAGE_SIZE = RegionListOption.pageSize(42L); private static final RegionListOption REGION_LIST_FILTER = RegionListOption.filter(REGION_FILTER); @@ -257,8 +263,8 @@ public class ComputeImplTest { private static final ZoneFilter ZONE_FILTER = ZoneFilter.notEquals(Compute.ZoneField.NAME, "someName"); private static final ZoneListOption ZONE_LIST_PAGE_TOKEN = - ZoneListOption.startPageToken("cursor"); - private static final ZoneListOption ZONE_LIST_MAX_RESULTS = ZoneListOption.pageSize(42L); + ZoneListOption.pageToken("cursor"); + private static final ZoneListOption ZONE_LIST_PAGE_SIZE = ZoneListOption.pageSize(42L); private static final ZoneListOption ZONE_LIST_FILTER = ZoneListOption.filter(ZONE_FILTER); private static final Map ZONE_LIST_OPTIONS = ImmutableMap.of( PAGE_TOKEN, "cursor", @@ -277,8 +283,8 @@ public class ComputeImplTest { private static final OperationFilter OPERATION_FILTER = OperationFilter.notEquals(Compute.OperationField.PROGRESS, 0); private static final OperationListOption OPERATION_LIST_PAGE_TOKEN = - OperationListOption.startPageToken("cursor"); - private static final OperationListOption OPERATION_LIST_MAX_RESULTS = + OperationListOption.pageToken("cursor"); + private static final OperationListOption OPERATION_LIST_PAGE_SIZE = OperationListOption.pageSize(42L); private static final OperationListOption OPERATION_LIST_FILTER = OperationListOption.filter(OPERATION_FILTER); @@ -287,6 +293,41 @@ public class ComputeImplTest { MAX_RESULTS, 42L, FILTER, "progress ne 0"); + // Address options + private static final Compute.AddressOption ADDRESS_OPTION_FIELDS = + Compute.AddressOption.fields(Compute.AddressField.ID, Compute.AddressField.DESCRIPTION); + + // Address list options + private static final Compute.AddressFilter ADDRESS_FILTER = + Compute.AddressFilter.notEquals(Compute.AddressField.REGION, "someRegion"); + private static final Compute.AddressListOption ADDRESS_LIST_PAGE_TOKEN = + Compute.AddressListOption.pageToken("cursor"); + private static final Compute.AddressListOption ADDRESS_LIST_PAGE_SIZE = + Compute.AddressListOption.pageSize(42L); + private static final Compute.AddressListOption ADDRESS_LIST_FILTER = + Compute.AddressListOption.filter(ADDRESS_FILTER); + private static final Map ADDRESS_LIST_OPTIONS = ImmutableMap.of( + PAGE_TOKEN, "cursor", + MAX_RESULTS, 42L, + FILTER, "region ne someRegion"); + + // Address aggregated list options + private static final Compute.AddressAggregatedListOption ADDRESS_AGGREGATED_LIST_PAGE_TOKEN = + Compute.AddressAggregatedListOption.pageToken("cursor"); + private static final Compute.AddressAggregatedListOption ADDRESS_AGGREGATED_LIST_PAGE_SIZE = + Compute.AddressAggregatedListOption.pageSize(42L); + private static final Compute.AddressAggregatedListOption ADDRESS_AGGREGATED_LIST_FILTER = + Compute.AddressAggregatedListOption.filter(ADDRESS_FILTER); + + private static final Function + OPERATION_TO_PB_FUNCTION = new Function() { + @Override + public com.google.api.services.compute.model.Operation apply(Operation operation) { + return operation.toPb(); + } + }; + private ComputeOptions options; private ComputeRpcFactory rpcFactoryMock; private ComputeRpc computeRpcMock; @@ -400,6 +441,16 @@ public void testGetDiskType() { assertEquals(DISK_TYPE, diskType); } + @Test + public void testGetDiskType_Null() { + EasyMock.expect( + computeRpcMock.getDiskType(DISK_TYPE_ID.zone(), DISK_TYPE_ID.diskType(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getDiskType(DISK_TYPE_ID.zone(), DISK_TYPE_ID.diskType())); + } + @Test public void testGetDiskTypeFromDiskTypeId() { EasyMock.expect( @@ -494,7 +545,7 @@ public void testListDiskTypesWithOptions() { EasyMock.expect(computeRpcMock.listDiskTypes(DISK_TYPE_ID.zone(), DISK_TYPE_LIST_OPTIONS)) .andReturn(result); EasyMock.replay(computeRpcMock); - Page page = compute.listDiskTypes(DISK_TYPE_ID.zone(), DISK_TYPE_LIST_MAX_RESULTS, + Page page = compute.listDiskTypes(DISK_TYPE_ID.zone(), DISK_TYPE_LIST_PAGE_SIZE, DISK_TYPE_LIST_PAGE_TOKEN, DISK_TYPE_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(diskTypeList.toArray(), Iterables.toArray(page.values(), DiskType.class)); @@ -559,7 +610,7 @@ public void testAggregatedListDiskTypesWithOptions() { Tuple.of(cursor, Iterables.transform(diskTypeList, DiskType.TO_PB_FUNCTION)); EasyMock.expect(computeRpcMock.listDiskTypes(DISK_TYPE_LIST_OPTIONS)).andReturn(result); EasyMock.replay(computeRpcMock); - Page page = compute.listDiskTypes(DISK_TYPE_AGGREGATED_LIST_MAX_RESULTS, + Page page = compute.listDiskTypes(DISK_TYPE_AGGREGATED_LIST_PAGE_SIZE, DISK_TYPE_AGGREGATED_LIST_PAGE_TOKEN, DISK_TYPE_AGGREGATED_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(diskTypeList.toArray(), Iterables.toArray(page.values(), DiskType.class)); @@ -578,6 +629,17 @@ public void testGetMachineType() { assertEquals(MACHINE_TYPE, machineType); } + @Test + public void testGetMachineType_Null() { + EasyMock.expect( + computeRpcMock.getMachineType( + MACHINE_TYPE_ID.zone(), MACHINE_TYPE_ID.machineType(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getMachineType(MACHINE_TYPE_ID.zone(), MACHINE_TYPE_ID.machineType())); + } + @Test public void testGetMachineTypeFromMachineTypeId() { EasyMock.expect(computeRpcMock.getMachineType( @@ -679,7 +741,7 @@ public void testListMachineTypesWithOptions() { .andReturn(result); EasyMock.replay(computeRpcMock); Page page = compute.listMachineTypes(MACHINE_TYPE_ID.zone(), - MACHINE_TYPE_LIST_MAX_RESULTS, MACHINE_TYPE_LIST_PAGE_TOKEN, MACHINE_TYPE_LIST_FILTER); + MACHINE_TYPE_LIST_PAGE_SIZE, MACHINE_TYPE_LIST_PAGE_TOKEN, MACHINE_TYPE_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(machineTypeList.toArray(), Iterables.toArray(page.values(), MachineType.class)); @@ -750,7 +812,7 @@ public void testAggregatedListMachineTypesWithOptions() { EasyMock.expect(computeRpcMock.listMachineTypes(MACHINE_TYPE_LIST_OPTIONS)) .andReturn(result); EasyMock.replay(computeRpcMock); - Page page = compute.listMachineTypes(MACHINE_TYPE_AGGREGATED_LIST_MAX_RESULTS, + Page page = compute.listMachineTypes(MACHINE_TYPE_AGGREGATED_LIST_PAGE_SIZE, MACHINE_TYPE_AGGREGATED_LIST_PAGE_TOKEN, MACHINE_TYPE_AGGREGATED_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(machineTypeList.toArray(), @@ -767,6 +829,15 @@ public void testGetRegion() { assertEquals(REGION, region); } + @Test + public void testGetRegion_Null() { + EasyMock.expect(computeRpcMock.getRegion(REGION_ID.region(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getRegion(REGION_ID.region())); + } + @Test public void testGetRegionWithSelectedFields() { Capture> capturedOptions = Capture.newInstance(); @@ -843,7 +914,7 @@ public void testListRegionsWithOptions() { Tuple.of(cursor, Iterables.transform(regionList, Region.TO_PB_FUNCTION)); EasyMock.expect(computeRpcMock.listRegions(REGION_LIST_OPTIONS)).andReturn(result); EasyMock.replay(computeRpcMock); - Page page = compute.listRegions(REGION_LIST_MAX_RESULTS, REGION_LIST_PAGE_TOKEN, + Page page = compute.listRegions(REGION_LIST_PAGE_SIZE, REGION_LIST_PAGE_TOKEN, REGION_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(regionList.toArray(), Iterables.toArray(page.values(), Region.class)); @@ -859,6 +930,14 @@ public void testGetZone() { assertEquals(ZONE, zone); } + @Test + public void testGetZone_Null() { + EasyMock.expect(computeRpcMock.getZone(ZONE_ID.zone(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getZone(ZONE_ID.zone())); + } + @Test public void testGetZoneWithSelectedFields() { Capture> capturedOptions = Capture.newInstance(); @@ -935,7 +1014,7 @@ public void testListZonesWithOptions() { EasyMock.expect(computeRpcMock.listZones(ZONE_LIST_OPTIONS)).andReturn(result); EasyMock.replay(computeRpcMock); Page page = - compute.listZones(ZONE_LIST_MAX_RESULTS, ZONE_LIST_PAGE_TOKEN, ZONE_LIST_FILTER); + compute.listZones(ZONE_LIST_PAGE_SIZE, ZONE_LIST_PAGE_TOKEN, ZONE_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(zoneList.toArray(), Iterables.toArray(page.values(), Zone.class)); } @@ -950,6 +1029,15 @@ public void testGetLicenseFromString() { assertEquals(LICENSE, license); } + @Test + public void testGetLicenseFromString_Null() { + EasyMock.expect(computeRpcMock.getLicense(PROJECT, LICENSE_ID.license(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getLicense(LICENSE_ID.license())); + } + @Test public void testGetLicenseFromStringWithOptions() { Capture> capturedOptions = Capture.newInstance(); @@ -997,6 +1085,17 @@ public void testGetLicenseFromId() { assertEquals(LICENSE, license); } + @Test + public void testGetLicenseFromId_Null() { + LicenseId licenseId = LicenseId.of("project2", "license2"); + EasyMock.expect( + computeRpcMock.getLicense(licenseId.project(), licenseId.license(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.getLicense(licenseId)); + } + @Test public void testGetGlobalOperation() { EasyMock.expect( @@ -1004,8 +1103,17 @@ public void testGetGlobalOperation() { .andReturn(globalOperation.toPb()); EasyMock.replay(computeRpcMock); compute = options.service(); - Operation operation = compute.get(GLOBAL_OPERATION_ID); - assertEquals(globalOperation, operation); + assertEquals(globalOperation, compute.get(GLOBAL_OPERATION_ID)); + } + + @Test + public void testGetGlobalOperation_Null() { + EasyMock.expect( + computeRpcMock.getGlobalOperation(GLOBAL_OPERATION_ID.operation(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.get(GLOBAL_OPERATION_ID)); } @Test @@ -1031,13 +1139,7 @@ public void testListGlobalOperations() { compute = options.service(); ImmutableList operationList = ImmutableList.of(globalOperation, globalOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); EasyMock.expect(computeRpcMock.listGlobalOperations(EMPTY_RPC_OPTIONS)).andReturn(result); EasyMock.replay(computeRpcMock); Page page = compute.listGlobalOperations(); @@ -1053,21 +1155,9 @@ public void testListGlobalOperationsNextPage() { ImmutableList operationList = ImmutableList.of(globalOperation, globalOperation); ImmutableList nextOperationList = ImmutableList.of(globalOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); Tuple> nextResult = - Tuple.of(nextCursor, Iterables.transform(nextOperationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(nextCursor, Iterables.transform(nextOperationList, OPERATION_TO_PB_FUNCTION)); Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); EasyMock.expect(computeRpcMock.listGlobalOperations(EMPTY_RPC_OPTIONS)).andReturn(result); EasyMock.expect(computeRpcMock.listGlobalOperations(nextOptions)).andReturn(nextResult); @@ -1101,16 +1191,10 @@ public void testListGlobalOperationsWithOptions() { compute = options.service(); ImmutableList operationList = ImmutableList.of(globalOperation, globalOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); EasyMock.expect(computeRpcMock.listGlobalOperations(OPERATION_LIST_OPTIONS)).andReturn(result); EasyMock.replay(computeRpcMock); - Page page = compute.listGlobalOperations(OPERATION_LIST_MAX_RESULTS, + Page page = compute.listGlobalOperations(OPERATION_LIST_PAGE_SIZE, OPERATION_LIST_PAGE_TOKEN, OPERATION_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(operationList.toArray(), Iterables.toArray(page.values(), Operation.class)); @@ -1145,6 +1229,17 @@ public void testGetRegionOperation() { assertEquals(regionOperation, operation); } + @Test + public void testGetRegionOperation_Null() { + EasyMock.expect(computeRpcMock.getRegionOperation(REGION_OPERATION_ID.region(), + REGION_OPERATION_ID.operation(), EMPTY_RPC_OPTIONS)) + .andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.get(REGION_OPERATION_ID); + assertEquals(regionOperation, operation); + } + @Test public void testGetRegionOperationWithSelectedFields() { Capture> capturedOptions = Capture.newInstance(); @@ -1168,13 +1263,7 @@ public void testListRegionOperations() { compute = options.service(); ImmutableList operationList = ImmutableList.of(regionOperation, regionOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); EasyMock.expect( computeRpcMock.listRegionOperations(REGION_OPERATION_ID.region(), EMPTY_RPC_OPTIONS)) .andReturn(result); @@ -1192,21 +1281,9 @@ public void testListRegionOperationsNextPage() { ImmutableList operationList = ImmutableList.of(regionOperation, regionOperation); ImmutableList nextOperationList = ImmutableList.of(regionOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); Tuple> nextResult = - Tuple.of(nextCursor, Iterables.transform(nextOperationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(nextCursor, Iterables.transform(nextOperationList, OPERATION_TO_PB_FUNCTION)); Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); EasyMock.expect(computeRpcMock.listRegionOperations(REGION_OPERATION_ID.region(), EMPTY_RPC_OPTIONS)).andReturn(result); @@ -1244,19 +1321,13 @@ public void testListRegionOperationsWithOptions() { compute = options.service(); ImmutableList operationList = ImmutableList.of(regionOperation, regionOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); EasyMock.expect( computeRpcMock.listRegionOperations(REGION_OPERATION_ID.region(), OPERATION_LIST_OPTIONS)) .andReturn(result); EasyMock.replay(computeRpcMock); Page page = compute.listRegionOperations(REGION_OPERATION_ID.region(), - OPERATION_LIST_MAX_RESULTS, OPERATION_LIST_PAGE_TOKEN, OPERATION_LIST_FILTER); + OPERATION_LIST_PAGE_SIZE, OPERATION_LIST_PAGE_TOKEN, OPERATION_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(operationList.toArray(), Iterables.toArray(page.values(), Operation.class)); } @@ -1282,14 +1353,22 @@ public void testDeleteRegionOperation_False() { @Test public void testGetZoneOperation() { EasyMock.expect(computeRpcMock.getZoneOperation(ZONE_OPERATION_ID.zone(), - ZONE_OPERATION_ID.operation(), EMPTY_RPC_OPTIONS)) - .andReturn(zoneOperation.toPb()); + ZONE_OPERATION_ID.operation(), EMPTY_RPC_OPTIONS)).andReturn(zoneOperation.toPb()); EasyMock.replay(computeRpcMock); compute = options.service(); Operation operation = compute.get(ZONE_OPERATION_ID); assertEquals(zoneOperation, operation); } + @Test + public void testGetZoneOperation_Null() { + EasyMock.expect(computeRpcMock.getZoneOperation(ZONE_OPERATION_ID.zone(), + ZONE_OPERATION_ID.operation(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.get(ZONE_OPERATION_ID)); + } + @Test public void testGetZoneOperationWithSelectedFields() { Capture> capturedOptions = Capture.newInstance(); @@ -1313,13 +1392,7 @@ public void testListZoneOperations() { compute = options.service(); ImmutableList operationList = ImmutableList.of(zoneOperation, zoneOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); EasyMock.expect( computeRpcMock.listZoneOperations(ZONE_OPERATION_ID.zone(), EMPTY_RPC_OPTIONS)) .andReturn(result); @@ -1337,21 +1410,9 @@ public void testListZoneOperationsNextPage() { ImmutableList operationList = ImmutableList.of(zoneOperation, zoneOperation); ImmutableList nextOperationList = ImmutableList.of(zoneOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); Tuple> nextResult = - Tuple.of(nextCursor, Iterables.transform(nextOperationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(nextCursor, Iterables.transform(nextOperationList, OPERATION_TO_PB_FUNCTION)); Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); EasyMock.expect(computeRpcMock.listZoneOperations(ZONE_OPERATION_ID.zone(), EMPTY_RPC_OPTIONS)) .andReturn(result); @@ -1389,19 +1450,13 @@ public void testListZoneOperationsWithOptions() { compute = options.service(); ImmutableList operationList = ImmutableList.of(zoneOperation, zoneOperation); Tuple> result = - Tuple.of(cursor, Iterables.transform(operationList, - new Function() { - @Override - public com.google.api.services.compute.model.Operation apply(Operation operation) { - return operation.toPb(); - } - })); + Tuple.of(cursor, Iterables.transform(operationList, OPERATION_TO_PB_FUNCTION)); EasyMock.expect( computeRpcMock.listZoneOperations(ZONE_OPERATION_ID.zone(), OPERATION_LIST_OPTIONS)) .andReturn(result); EasyMock.replay(computeRpcMock); Page page = compute.listZoneOperations(ZONE_OPERATION_ID.zone(), - OPERATION_LIST_MAX_RESULTS, OPERATION_LIST_PAGE_TOKEN, OPERATION_LIST_FILTER); + OPERATION_LIST_PAGE_SIZE, OPERATION_LIST_PAGE_TOKEN, OPERATION_LIST_FILTER); assertEquals(cursor, page.nextPageCursor()); assertArrayEquals(operationList.toArray(), Iterables.toArray(page.values(), Operation.class)); } @@ -1424,6 +1479,433 @@ public void testDeleteZoneOperation_False() { assertFalse(compute.delete(ZONE_OPERATION_ID)); } + @Test + public void testGetGlobalAddress() { + EasyMock.expect(computeRpcMock.getGlobalAddress(GLOBAL_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)) + .andReturn(GLOBAL_ADDRESS.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Address address = compute.get(GLOBAL_ADDRESS_ID); + assertEquals(new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS)), address); + } + + @Test + public void testGetGlobalAddress_Null() { + EasyMock.expect(computeRpcMock.getGlobalAddress(GLOBAL_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.get(GLOBAL_ADDRESS_ID)); + } + + @Test + public void testGetGlobalAddressWithSelectedFields() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.getGlobalAddress( + eq(GLOBAL_ADDRESS_ID.address()), capture(capturedOptions))) + .andReturn(GLOBAL_ADDRESS.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Address address = compute.get(GLOBAL_ADDRESS_ID, ADDRESS_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(ADDRESS_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS)), address); + } + + @Test + public void testGetRegionAddress() { + EasyMock.expect(computeRpcMock.getRegionAddress(REGION_ADDRESS_ID.region(), + REGION_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)).andReturn(REGION_ADDRESS.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Address address = compute.get(REGION_ADDRESS_ID); + assertEquals(new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), address); + } + + @Test + public void testGetRegionAddress_Null() { + EasyMock.expect(computeRpcMock.getRegionAddress(REGION_ADDRESS_ID.region(), + REGION_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)).andReturn(REGION_ADDRESS.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Address address = compute.get(REGION_ADDRESS_ID); + assertEquals(new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), address); + } + + @Test + public void testGetRegionAddressWithSelectedFields() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.getRegionAddress(eq(REGION_ADDRESS_ID.region()), + eq(REGION_ADDRESS_ID.address()), capture(capturedOptions))) + .andReturn(REGION_ADDRESS.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Address address = compute.get(REGION_ADDRESS_ID, ADDRESS_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(ADDRESS_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), address); + } + + @Test + public void testDeleteGlobalAddress_Operation() { + EasyMock + .expect(computeRpcMock.deleteGlobalAddress(GLOBAL_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)) + .andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(globalOperation, compute.delete(GLOBAL_ADDRESS_ID)); + } + + @Test + public void testDeleteGlobalAddressWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.deleteGlobalAddress(eq(GLOBAL_ADDRESS_ID.address()), + capture(capturedOptions))).andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.delete(GLOBAL_ADDRESS_ID, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(globalOperation, operation); + } + + @Test + public void testDeleteGlobalAddress_Null() { + EasyMock + .expect(computeRpcMock.deleteGlobalAddress(GLOBAL_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)) + .andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.delete(GLOBAL_ADDRESS_ID)); + } + + @Test + public void testDeleteRegionAddress_Operation() { + EasyMock.expect(computeRpcMock.deleteRegionAddress(REGION_ADDRESS_ID.region(), + REGION_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)).andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertEquals(regionOperation, compute.delete(REGION_ADDRESS_ID)); + } + + @Test + public void testDeleteRegionAddressWithSelectedFields_Operation() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.deleteRegionAddress(eq(REGION_ADDRESS_ID.region()), + eq(REGION_ADDRESS_ID.address()), capture(capturedOptions))) + .andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.delete(REGION_ADDRESS_ID, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(globalOperation, operation); + } + + @Test + public void testDeleteRegionAddress_Null() { + EasyMock.expect(computeRpcMock.deleteRegionAddress(REGION_ADDRESS_ID.region(), + REGION_ADDRESS_ID.address(), EMPTY_RPC_OPTIONS)).andReturn(null); + EasyMock.replay(computeRpcMock); + compute = options.service(); + assertNull(compute.delete(REGION_ADDRESS_ID)); + } + + @Test + public void testListGlobalAddresses() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listGlobalAddresses(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page
page = compute.listGlobalAddresses(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testListGlobalAddressesNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS))); + ImmutableList
nextAddressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, Iterables.transform(nextAddressList, AddressInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect(computeRpcMock.listGlobalAddresses(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.expect(computeRpcMock.listGlobalAddresses(nextOptions)).andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page
page = compute.listGlobalAddresses(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextAddressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testListEmptyGlobalAddresses() { + ImmutableList addresses = ImmutableList.of(); + Tuple> result = + Tuple.>of(null, addresses); + EasyMock.expect(computeRpcMock.listGlobalAddresses(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Page
page = compute.listGlobalAddresses(); + assertNull(page.nextPageCursor()); + assertArrayEquals(addresses.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testListGlobalAddressesWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(GLOBAL_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listGlobalAddresses(ADDRESS_LIST_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page
page = compute.listGlobalAddresses(ADDRESS_LIST_PAGE_SIZE, + ADDRESS_LIST_PAGE_TOKEN, ADDRESS_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testListRegionAddresses() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + EasyMock.expect( + computeRpcMock.listRegionAddresses(REGION_ADDRESS_ID.region(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page
page = compute.listRegionAddresses(REGION_ADDRESS_ID.region()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testListRegionAddressesNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + ImmutableList
nextAddressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, Iterables.transform(nextAddressList, AddressInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect( + computeRpcMock.listRegionAddresses(REGION_ADDRESS_ID.region(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.expect( + computeRpcMock.listRegionAddresses(REGION_ADDRESS_ID.region(), nextOptions)) + .andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page
page = compute.listRegionAddresses(REGION_ADDRESS_ID.region()); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextAddressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testListEmptyRegionAddresses() { + ImmutableList addresses = ImmutableList.of(); + Tuple> result = + Tuple.>of(null, addresses); + EasyMock.expect( + computeRpcMock.listRegionAddresses(REGION_ADDRESS_ID.region(), EMPTY_RPC_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Page
page = compute.listRegionAddresses(REGION_ADDRESS_ID.region()); + assertNull(page.nextPageCursor()); + assertArrayEquals(addresses.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testListRegionAddressesWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + EasyMock.expect( + computeRpcMock.listRegionAddresses(REGION_ADDRESS_ID.region(), ADDRESS_LIST_OPTIONS)) + .andReturn(result); + EasyMock.replay(computeRpcMock); + Page
page = compute.listRegionAddresses(REGION_ADDRESS_ID.region(), + ADDRESS_LIST_PAGE_SIZE, ADDRESS_LIST_PAGE_TOKEN, ADDRESS_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testAggregatedListAddresses() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listAddresses(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page
page = compute.listAddresses(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testAggregatedListAddressesNextPage() { + String cursor = "cursor"; + String nextCursor = "nextCursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + ImmutableList
nextAddressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + Tuple> nextResult = + Tuple.of(nextCursor, Iterables.transform(nextAddressList, AddressInfo.TO_PB_FUNCTION)); + Map nextOptions = ImmutableMap.of(PAGE_TOKEN, cursor); + EasyMock.expect(computeRpcMock.listAddresses(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.expect(computeRpcMock.listAddresses(nextOptions)).andReturn(nextResult); + EasyMock.replay(computeRpcMock); + Page
page = compute.listAddresses(); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + page = page.nextPage(); + assertEquals(nextCursor, page.nextPageCursor()); + assertArrayEquals(nextAddressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testAggregatedListEmptyAddresses() { + ImmutableList addresses = ImmutableList.of(); + Tuple> result = + Tuple.>of(null, addresses); + EasyMock.expect(computeRpcMock.listAddresses(EMPTY_RPC_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Page
page = compute.listAddresses(); + assertNull(page.nextPageCursor()); + assertArrayEquals(addresses.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testAggregatedListAddressesWithOptions() { + String cursor = "cursor"; + compute = options.service(); + ImmutableList
addressList = ImmutableList.of( + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS)), + new Address(compute, new AddressInfo.BuilderImpl(REGION_ADDRESS))); + Tuple> result = + Tuple.of(cursor, Iterables.transform(addressList, AddressInfo.TO_PB_FUNCTION)); + EasyMock.expect(computeRpcMock.listAddresses(ADDRESS_LIST_OPTIONS)).andReturn(result); + EasyMock.replay(computeRpcMock); + Page
page = compute.listAddresses(ADDRESS_AGGREGATED_LIST_PAGE_SIZE, + ADDRESS_AGGREGATED_LIST_PAGE_TOKEN, ADDRESS_AGGREGATED_LIST_FILTER); + assertEquals(cursor, page.nextPageCursor()); + assertArrayEquals(addressList.toArray(), Iterables.toArray(page.values(), Address.class)); + } + + @Test + public void testCreateGlobalAddress() { + EasyMock.expect(computeRpcMock.createGlobalAddress(GLOBAL_ADDRESS.toPb(), EMPTY_RPC_OPTIONS)) + .andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + AddressId incompleteId = GlobalAddressId.of("address"); + Operation operation = + compute.create(GLOBAL_ADDRESS.toBuilder().addressId(incompleteId).build()); + assertEquals(globalOperation, operation); + } + + @Test + public void testCreateGlobalAddressWithOptions() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect( + computeRpcMock.createGlobalAddress(eq(GLOBAL_ADDRESS.toPb()), capture(capturedOptions))) + .andReturn(globalOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.create(GLOBAL_ADDRESS, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(globalOperation, operation); + } + + @Test + public void testCreateRegionAddress() { + EasyMock.expect(computeRpcMock.createRegionAddress(REGION_ADDRESS_ID.region(), + REGION_ADDRESS.toPb(), EMPTY_RPC_OPTIONS)).andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + AddressId incompleteId = RegionAddressId.of("region", "address"); + Operation operation = + compute.create(REGION_ADDRESS.toBuilder().addressId(incompleteId).build()); + assertEquals(regionOperation, operation); + } + + @Test + public void testCreateRegionAddressWithOptions() { + Capture> capturedOptions = Capture.newInstance(); + EasyMock.expect(computeRpcMock.createRegionAddress(eq(REGION_ADDRESS_ID.region()), + eq(REGION_ADDRESS.toPb()), capture(capturedOptions))).andReturn(regionOperation.toPb()); + EasyMock.replay(computeRpcMock); + compute = options.service(); + Operation operation = compute.create(REGION_ADDRESS, OPERATION_OPTION_FIELDS); + String selector = (String) capturedOptions.getValue().get(OPERATION_OPTION_FIELDS.rpcOption()); + assertTrue(selector.contains("selfLink")); + assertTrue(selector.contains("id")); + assertTrue(selector.contains("description")); + assertEquals(23, selector.length()); + assertEquals(regionOperation, operation); + } + @Test public void testRetryableException() { EasyMock.expect( diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskTypeTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskTypeTest.java index 7cacf256523a..9e97b8d1becd 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskTypeTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskTypeTest.java @@ -20,8 +20,6 @@ import org.junit.Test; -import java.math.BigInteger; - public class DiskTypeTest { private static final String ID = "42"; diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ForwardingRuleIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ForwardingRuleIdTest.java new file mode 100644 index 000000000000..9a6ab4b8668e --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ForwardingRuleIdTest.java @@ -0,0 +1,139 @@ +/* + * 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.gcloud.compute; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class ForwardingRuleIdTest { + + private static final String PROJECT = "project"; + private static final String REGION = "region"; + private static final String NAME = "rule"; + private static final String GLOBAL_URL = + "https://www.googleapis.com/compute/v1/projects/project/global/forwardingRules/rule"; + private static final String REGION_URL = "https://www.googleapis.com/compute/v1/projects/" + + "project/regions/region/forwardingRules/rule"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testOf() { + GlobalForwardingRuleId forwardingRuleId = GlobalForwardingRuleId.of(PROJECT, NAME); + assertEquals(PROJECT, forwardingRuleId.project()); + assertEquals(NAME, forwardingRuleId.rule()); + assertEquals(GLOBAL_URL, forwardingRuleId.selfLink()); + assertEquals(ForwardingRuleId.Type.GLOBAL, forwardingRuleId.type()); + forwardingRuleId = GlobalForwardingRuleId.of(NAME); + assertNull(forwardingRuleId.project()); + assertEquals(NAME, forwardingRuleId.rule()); + assertEquals(ForwardingRuleId.Type.GLOBAL, forwardingRuleId.type()); + RegionForwardingRuleId regionForwardingRuleId = + RegionForwardingRuleId.of(PROJECT, REGION, NAME); + assertEquals(PROJECT, regionForwardingRuleId.project()); + assertEquals(REGION, regionForwardingRuleId.region()); + assertEquals(NAME, regionForwardingRuleId.rule()); + assertEquals(REGION_URL, regionForwardingRuleId.selfLink()); + assertEquals(ForwardingRuleId.Type.REGION, regionForwardingRuleId.type()); + regionForwardingRuleId = RegionForwardingRuleId.of(RegionId.of(PROJECT, REGION), NAME); + assertEquals(PROJECT, regionForwardingRuleId.project()); + assertEquals(REGION, regionForwardingRuleId.region()); + assertEquals(NAME, regionForwardingRuleId.rule()); + assertEquals(REGION_URL, regionForwardingRuleId.selfLink()); + assertEquals(ForwardingRuleId.Type.REGION, regionForwardingRuleId.type()); + regionForwardingRuleId = RegionForwardingRuleId.of(REGION, NAME); + assertNull(regionForwardingRuleId.project()); + assertEquals(REGION, regionForwardingRuleId.region()); + assertEquals(NAME, regionForwardingRuleId.rule()); + assertEquals(ForwardingRuleId.Type.REGION, regionForwardingRuleId.type()); + } + + @Test + public void testToAndFromUrlGlobal() { + GlobalForwardingRuleId forwardingRuleId = GlobalForwardingRuleId.of(PROJECT, NAME); + compareGlobalForwardingRuleId(forwardingRuleId, + GlobalForwardingRuleId.fromUrl(forwardingRuleId.selfLink())); + RegionForwardingRuleId regionForwardingRuleId = + RegionForwardingRuleId.of(PROJECT, REGION, NAME); + compareRegionForwardingRuleId(regionForwardingRuleId, + RegionForwardingRuleId.fromUrl(regionForwardingRuleId.selfLink())); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("notMatchingUrl is not a valid global forwarding rule URL"); + GlobalForwardingRuleId.fromUrl("notMatchingUrl"); + } + + @Test + public void testToAndFromUrlRegion() { + RegionForwardingRuleId regionForwardingRuleId = + RegionForwardingRuleId.of(PROJECT, REGION, NAME); + compareRegionForwardingRuleId(regionForwardingRuleId, + RegionForwardingRuleId.fromUrl(regionForwardingRuleId.selfLink())); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("notMatchingUrl is not a valid region forwarding rule URL"); + RegionForwardingRuleId.fromUrl("notMatchingUrl"); + } + + @Test + public void testSetProjectId() { + GlobalForwardingRuleId forwardingRuleId = GlobalForwardingRuleId.of(PROJECT, NAME); + assertSame(forwardingRuleId, forwardingRuleId.setProjectId(PROJECT)); + compareGlobalForwardingRuleId(forwardingRuleId, + GlobalForwardingRuleId.of(NAME).setProjectId(PROJECT)); + RegionForwardingRuleId regionForwardingRuleId = + RegionForwardingRuleId.of(PROJECT, REGION, NAME); + assertSame(regionForwardingRuleId, regionForwardingRuleId.setProjectId(PROJECT)); + compareRegionForwardingRuleId(regionForwardingRuleId, + RegionForwardingRuleId.of(REGION, NAME).setProjectId(PROJECT)); + } + + @Test + public void testMatchesUrl() { + assertTrue(GlobalForwardingRuleId.matchesUrl( + GlobalForwardingRuleId.of(PROJECT, NAME).selfLink())); + assertFalse(GlobalForwardingRuleId.matchesUrl("notMatchingUrl")); + assertTrue(RegionForwardingRuleId.matchesUrl( + RegionForwardingRuleId.of(PROJECT, REGION, NAME).selfLink())); + assertFalse(RegionForwardingRuleId.matchesUrl("notMatchingUrl")); + } + + private void compareGlobalForwardingRuleId(GlobalForwardingRuleId expected, + GlobalForwardingRuleId value) { + assertEquals(expected, value); + assertEquals(expected.project(), expected.project()); + assertEquals(expected.rule(), expected.rule()); + assertEquals(expected.selfLink(), expected.selfLink()); + assertEquals(expected.hashCode(), expected.hashCode()); + } + + private void compareRegionForwardingRuleId(RegionForwardingRuleId expected, + RegionForwardingRuleId value) { + assertEquals(expected, value); + assertEquals(expected.project(), expected.project()); + assertEquals(expected.region(), expected.region()); + assertEquals(expected.rule(), expected.rule()); + assertEquals(expected.selfLink(), expected.selfLink()); + assertEquals(expected.hashCode(), expected.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/InstanceIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/InstanceIdTest.java new file mode 100644 index 000000000000..782c8eb4ec31 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/InstanceIdTest.java @@ -0,0 +1,88 @@ +/* + * 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.gcloud.compute; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class InstanceIdTest { + + private static final String PROJECT = "project"; + private static final String ZONE = "zone"; + private static final String NAME = "instance"; + private static final String URL = + "https://www.googleapis.com/compute/v1/projects/project/zones/zone/instances/instance"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testOf() { + InstanceId instanceId = InstanceId.of(PROJECT, ZONE, NAME); + assertEquals(PROJECT, instanceId.project()); + assertEquals(ZONE, instanceId.zone()); + assertEquals(NAME, instanceId.instance()); + assertEquals(URL, instanceId.selfLink()); + instanceId = InstanceId.of(ZoneId.of(PROJECT, ZONE), NAME); + assertEquals(PROJECT, instanceId.project()); + assertEquals(ZONE, instanceId.zone()); + assertEquals(NAME, instanceId.instance()); + assertEquals(URL, instanceId.selfLink()); + instanceId = InstanceId.of(ZONE, NAME); + assertNull(instanceId.project()); + assertEquals(ZONE, instanceId.zone()); + assertEquals(NAME, instanceId.instance()); + } + + @Test + public void testToAndFromUrl() { + InstanceId instanceId = InstanceId.of(PROJECT, ZONE, NAME); + compareInstanceId(instanceId, InstanceId.fromUrl(instanceId.selfLink())); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("notMatchingUrl is not a valid instance URL"); + InstanceId.fromUrl("notMatchingUrl"); + } + + @Test + public void testSetProjectId() { + InstanceId instanceId = InstanceId.of(PROJECT, ZONE, NAME); + assertSame(instanceId, instanceId.setProjectId(PROJECT)); + compareInstanceId(instanceId, InstanceId.of(ZONE, NAME).setProjectId(PROJECT)); + } + + @Test + public void testMatchesUrl() { + assertTrue(InstanceId.matchesUrl(InstanceId.of(PROJECT, ZONE, NAME).selfLink())); + assertFalse(InstanceId.matchesUrl("notMatchingUrl")); + } + + private void compareInstanceId(InstanceId expected, InstanceId value) { + assertEquals(expected, value); + assertEquals(expected.project(), expected.project()); + assertEquals(expected.zone(), expected.zone()); + assertEquals(expected.instance(), expected.instance()); + assertEquals(expected.selfLink(), expected.selfLink()); + assertEquals(expected.hashCode(), expected.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/RegionTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/RegionTest.java index 072823933110..fb0250366a5e 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/RegionTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/RegionTest.java @@ -22,7 +22,6 @@ import org.junit.Test; -import java.math.BigInteger; import java.util.List; public class RegionTest { diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java index a73cf860810f..81afee4acf50 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SerializationTest.java @@ -126,6 +126,27 @@ public class SerializationTest { new Operation.Builder(COMPUTE).operationId(ZONE_OPERATION_ID).build(); private static final Operation REGION_OPERATION = new Operation.Builder(COMPUTE).operationId(REGION_OPERATION_ID).build(); + private static final InstanceId INSTANCE_ID = InstanceId.of("project", "zone", "instance"); + private static final GlobalForwardingRuleId GLOBAL_FORWARDING_RULE_ID = + GlobalForwardingRuleId.of("project", "rule"); + private static final RegionForwardingRuleId REGION_FORWARDING_RULE_ID = + RegionForwardingRuleId.of("project", "region", "rule"); + private static final GlobalAddressId GLOBAL_ADDRESS_ID = GlobalAddressId.of("project", "address"); + private static final RegionAddressId REGION_ADDRESS_ID = + RegionAddressId.of("project", "region", "address"); + private static final AddressInfo.InstanceUsage INSTANCE_USAGE = + new AddressInfo.InstanceUsage(INSTANCE_ID); + private static final AddressInfo.GlobalForwardingUsage GLOBAL_FORWARDING_USAGE = + new AddressInfo.GlobalForwardingUsage(ImmutableList.of(GLOBAL_FORWARDING_RULE_ID)); + private static final AddressInfo.RegionForwardingUsage REGION_FORWARDING_USAGE = + new AddressInfo.RegionForwardingUsage(ImmutableList.of(REGION_FORWARDING_RULE_ID)); + private static final AddressInfo ADDRESS_INFO = AddressInfo.builder(REGION_ADDRESS_ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .id(ID) + .usage(INSTANCE_USAGE) + .build(); + private static final Address ADDRESS = new Address.Builder(COMPUTE, REGION_ADDRESS_ID).build(); private static final Compute.DiskTypeOption DISK_TYPE_OPTION = Compute.DiskTypeOption.fields(); private static final Compute.DiskTypeFilter DISK_TYPE_FILTER = @@ -158,6 +179,14 @@ public class SerializationTest { Compute.OperationFilter.equals(Compute.OperationField.SELF_LINK, "selfLink"); private static final Compute.OperationListOption OPERATION_LIST_OPTION = Compute.OperationListOption.filter(OPERATION_FILTER); + private static final Compute.AddressOption ADDRESS_OPTION = Compute.AddressOption.fields(); + private static final Compute.AddressFilter ADDRESS_FILTER = + Compute.AddressFilter.equals(Compute.AddressField.SELF_LINK, "selfLink"); + private static final Compute.AddressListOption ADDRESS_LIST_OPTION = + Compute.AddressListOption.filter(ADDRESS_FILTER); + private static final Compute.AddressAggregatedListOption ADDRESS_AGGREGATED_LIST_OPTION = + Compute.AddressAggregatedListOption.filter(ADDRESS_FILTER); + @Test public void testServiceOptions() throws Exception { ComputeOptions options = ComputeOptions.builder() @@ -181,11 +210,14 @@ public void testModelAndRequests() throws Exception { Serializable[] objects = {DISK_TYPE_ID, DISK_TYPE, MACHINE_TYPE_ID, MACHINE_TYPE, REGION_ID, REGION, ZONE_ID, ZONE, LICENSE_ID, LICENSE, DEPRECATION_STATUS, GLOBAL_OPERATION_ID, REGION_OPERATION_ID, ZONE_OPERATION_ID, GLOBAL_OPERATION, REGION_OPERATION, ZONE_OPERATION, - DISK_TYPE_OPTION, DISK_TYPE_FILTER, DISK_TYPE_LIST_OPTION, DISK_TYPE_AGGREGATED_LIST_OPTION, - MACHINE_TYPE_OPTION, MACHINE_TYPE_FILTER, MACHINE_TYPE_LIST_OPTION, - MACHINE_TYPE_AGGREGATED_LIST_OPTION, REGION_OPTION, REGION_FILTER, REGION_LIST_OPTION, - ZONE_OPTION, ZONE_FILTER, ZONE_LIST_OPTION, LICENSE_OPTION, OPERATION_OPTION, - OPERATION_FILTER, OPERATION_LIST_OPTION}; + INSTANCE_ID, REGION_FORWARDING_RULE_ID, GLOBAL_FORWARDING_RULE_ID, GLOBAL_ADDRESS_ID, + REGION_ADDRESS_ID, INSTANCE_USAGE, GLOBAL_FORWARDING_USAGE, REGION_FORWARDING_USAGE, + ADDRESS_INFO, ADDRESS, DISK_TYPE_OPTION, DISK_TYPE_FILTER, DISK_TYPE_LIST_OPTION, + DISK_TYPE_AGGREGATED_LIST_OPTION, MACHINE_TYPE_OPTION, MACHINE_TYPE_FILTER, + MACHINE_TYPE_LIST_OPTION, MACHINE_TYPE_AGGREGATED_LIST_OPTION, REGION_OPTION, REGION_FILTER, + REGION_LIST_OPTION, ZONE_OPTION, ZONE_FILTER, ZONE_LIST_OPTION, LICENSE_OPTION, + OPERATION_OPTION, OPERATION_FILTER, OPERATION_LIST_OPTION, ADDRESS_OPTION, ADDRESS_FILTER, + ADDRESS_LIST_OPTION, ADDRESS_AGGREGATED_LIST_OPTION}; for (Serializable obj : objects) { Object copy = serializeAndDeserialize(obj); assertEquals(obj, obj); diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ZoneTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ZoneTest.java index bdc96d3d9069..d686054b8cf6 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ZoneTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/ZoneTest.java @@ -23,7 +23,6 @@ import org.junit.Test; -import java.math.BigInteger; import java.util.List; public class ZoneTest { diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java index 56960903d6c7..666fe8500704 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/it/ITComputeTest.java @@ -23,14 +23,20 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import com.google.common.collect.ImmutableSet; import com.google.gcloud.Page; +import com.google.gcloud.compute.Address; +import com.google.gcloud.compute.AddressId; +import com.google.gcloud.compute.AddressInfo; import com.google.gcloud.compute.Compute; import com.google.gcloud.compute.DiskType; +import com.google.gcloud.compute.GlobalAddressId; import com.google.gcloud.compute.License; import com.google.gcloud.compute.LicenseId; import com.google.gcloud.compute.MachineType; import com.google.gcloud.compute.Operation; import com.google.gcloud.compute.Region; +import com.google.gcloud.compute.RegionAddressId; import com.google.gcloud.compute.RegionOperationId; import com.google.gcloud.compute.Zone; import com.google.gcloud.compute.ZoneOperationId; @@ -42,6 +48,7 @@ import org.junit.rules.Timeout; import java.util.Iterator; +import java.util.Set; public class ITComputeTest { @@ -50,6 +57,7 @@ public class ITComputeTest { private static final String DISK_TYPE = "local-ssd"; private static final String MACHINE_TYPE = "f1-micro"; private static final LicenseId LICENSE_ID = LicenseId.of("ubuntu-os-cloud", "ubuntu-1404-trusty"); + private static final String BASE_RESOURCE_NAME = RemoteComputeHelper.baseResourceName(); private static Compute compute; @@ -65,7 +73,6 @@ public static void beforeClass() { @Test public void testGetDiskType() { DiskType diskType = compute.getDiskType(ZONE, DISK_TYPE); - // todo(mziccard): uncomment or remove once #695 is closed // assertNotNull(diskType.id()); assertEquals(ZONE, diskType.diskTypeId().zone()); assertEquals(DISK_TYPE, diskType.diskTypeId().diskType()); @@ -79,7 +86,6 @@ public void testGetDiskType() { public void testGetDiskTypeWithSelectedFields() { DiskType diskType = compute.getDiskType(ZONE, DISK_TYPE, Compute.DiskTypeOption.fields(Compute.DiskTypeField.CREATION_TIMESTAMP)); - // todo(mziccard): uncomment or remove once #695 is closed // assertNotNull(diskType.id()); assertEquals(ZONE, diskType.diskTypeId().zone()); assertEquals(DISK_TYPE, diskType.diskTypeId().diskType()); @@ -96,7 +102,6 @@ public void testListDiskTypes() { assertTrue(diskTypeIterator.hasNext()); while (diskTypeIterator.hasNext()) { DiskType diskType = diskTypeIterator.next(); - // todo(mziccard): uncomment or remove once #695 is closed // assertNotNull(diskType.id()); assertNotNull(diskType.diskTypeId()); assertEquals(ZONE, diskType.diskTypeId().zone()); @@ -309,7 +314,7 @@ public void testAggregatedListMachineTypesWithFilter() { @Test public void testGetLicense() { - License license= compute.getLicense(LICENSE_ID); + License license = compute.getLicense(LICENSE_ID); assertEquals(LICENSE_ID, license.licenseId()); assertNotNull(license.chargesUseFee()); } @@ -637,4 +642,217 @@ public void testListZoneOperationsWithFilter() { assertNotNull(operation.user()); } } + + @Test + public void testCreateGetAndDeleteRegionAddress() throws InterruptedException { + String name = BASE_RESOURCE_NAME + "create-and-get-region-address"; + AddressId addressId = RegionAddressId.of(REGION, name); + AddressInfo addressInfo = AddressInfo.of(addressId); + Operation operation = compute.create(addressInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + // test get + Address remoteAddress = compute.get(addressId); + assertNotNull(remoteAddress); + assertTrue(remoteAddress.addressId() instanceof RegionAddressId); + assertEquals(REGION, remoteAddress.addressId().region()); + assertEquals(addressId.address(), remoteAddress.addressId().address()); + assertNotNull(remoteAddress.address()); + assertNotNull(remoteAddress.creationTimestamp()); + assertNotNull(remoteAddress.id()); + assertNotNull(remoteAddress.status()); + // test get with selected fields + remoteAddress = compute.get(addressId, Compute.AddressOption.fields()); + assertNotNull(remoteAddress); + assertTrue(remoteAddress.addressId() instanceof RegionAddressId); + assertEquals(REGION, remoteAddress.addressId().region()); + assertEquals(addressId.address(), remoteAddress.addressId().address()); + assertNull(remoteAddress.address()); + assertNull(remoteAddress.creationTimestamp()); + assertNull(remoteAddress.id()); + operation = remoteAddress.delete(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + assertNull(compute.get(addressId)); + } + + @Test + public void testListRegionAddresses() throws InterruptedException { + String prefix = BASE_RESOURCE_NAME + "list-region-address"; + String[] addressNames = {prefix + "1", prefix + "2"}; + AddressId firstAddressId = RegionAddressId.of(REGION, addressNames[0]); + AddressId secondAddressId = RegionAddressId.of(REGION, addressNames[1]); + Operation firstOperation = compute.create(AddressInfo.of(firstAddressId)); + Operation secondOperation = compute.create(AddressInfo.of(secondAddressId)); + while (!firstOperation.isDone()) { + Thread.sleep(1000L); + } + while (!secondOperation.isDone()) { + Thread.sleep(1000L); + } + Set addressSet = ImmutableSet.copyOf(addressNames); + // test list + Compute.AddressFilter filter = + Compute.AddressFilter.equals(Compute.AddressField.NAME, prefix + "\\d"); + Page
addressPage = + compute.listRegionAddresses(REGION, Compute.AddressListOption.filter(filter)); + Iterator
addressIterator = addressPage.iterateAll(); + int count = 0; + while (addressIterator.hasNext()) { + Address address = addressIterator.next(); + assertNotNull(address.addressId()); + assertTrue(address.addressId() instanceof RegionAddressId); + assertEquals(REGION, address.addressId().region()); + assertTrue(addressSet.contains(address.addressId().address())); + assertNotNull(address.address()); + assertNotNull(address.creationTimestamp()); + assertNotNull(address.id()); + count++; + } + assertEquals(2, count); + // test list with selected fields + count = 0; + addressPage = compute.listRegionAddresses(REGION, Compute.AddressListOption.filter(filter), + Compute.AddressListOption.fields(Compute.AddressField.ADDRESS)); + addressIterator = addressPage.iterateAll(); + while (addressIterator.hasNext()) { + Address address = addressIterator.next(); + assertTrue(address.addressId() instanceof RegionAddressId); + assertEquals(REGION, address.addressId().region()); + assertTrue(addressSet.contains(address.addressId().address())); + assertNotNull(address.address()); + assertNull(address.creationTimestamp()); + assertNull(address.id()); + assertNull(address.status()); + assertNull(address.usage()); + count++; + } + assertEquals(2, count); + compute.delete(firstAddressId); + compute.delete(secondAddressId); + } + + @Test + public void testAggregatedListAddresses() throws InterruptedException { + String prefix = BASE_RESOURCE_NAME + "aggregated-list-address"; + String[] addressNames = {prefix + "1", prefix + "2"}; + AddressId firstAddressId = RegionAddressId.of(REGION, addressNames[0]); + AddressId secondAddressId = GlobalAddressId.of(REGION, addressNames[1]); + Operation firstOperation = compute.create(AddressInfo.of(firstAddressId)); + Operation secondOperation = compute.create(AddressInfo.of(secondAddressId)); + while (!firstOperation.isDone()) { + Thread.sleep(1000L); + } + while (!secondOperation.isDone()) { + Thread.sleep(1000L); + } + Set addressSet = ImmutableSet.copyOf(addressNames); + Compute.AddressFilter filter = + Compute.AddressFilter.equals(Compute.AddressField.NAME, prefix + "\\d"); + Page
addressPage = + compute.listAddresses(Compute.AddressAggregatedListOption.filter(filter)); + Iterator
addressIterator = addressPage.iterateAll(); + int count = 0; + while (addressIterator.hasNext()) { + Address address = addressIterator.next(); + assertNotNull(address.addressId()); + assertTrue(addressSet.contains(address.addressId().address())); + assertNotNull(address.address()); + assertNotNull(address.creationTimestamp()); + assertNotNull(address.id()); + count++; + } + assertEquals(2, count); + compute.delete(firstAddressId); + compute.delete(secondAddressId); + } + + @Test + public void testCreateGetAndDeleteGlobalAddress() throws InterruptedException { + String name = BASE_RESOURCE_NAME + "create-and-get-global-address"; + AddressId addressId = GlobalAddressId.of(name); + AddressInfo addressInfo = AddressInfo.of(addressId); + Operation operation = compute.create(addressInfo); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + // test get + Address remoteAddress = compute.get(addressId); + assertNotNull(remoteAddress); + assertTrue(remoteAddress.addressId() instanceof GlobalAddressId); + assertEquals(addressId.address(), remoteAddress.addressId().address()); + assertNotNull(remoteAddress.address()); + assertNotNull(remoteAddress.creationTimestamp()); + assertNotNull(remoteAddress.id()); + assertNotNull(remoteAddress.status()); + // test get with selected fields + remoteAddress = compute.get(addressId, Compute.AddressOption.fields()); + assertNotNull(remoteAddress); + assertTrue(remoteAddress.addressId() instanceof GlobalAddressId); + assertEquals(addressId.address(), remoteAddress.addressId().address()); + assertNull(remoteAddress.address()); + assertNull(remoteAddress.creationTimestamp()); + assertNull(remoteAddress.id()); + operation = remoteAddress.delete(); + while (!operation.isDone()) { + Thread.sleep(1000L); + } + assertNull(compute.get(addressId)); + } + + @Test + public void testListGlobalAddresses() throws InterruptedException { + String prefix = BASE_RESOURCE_NAME + "list-global-address"; + String[] addressNames = {prefix + "1", prefix + "2"}; + AddressId firstAddressId = GlobalAddressId.of(addressNames[0]); + AddressId secondAddressId = GlobalAddressId.of(addressNames[1]); + Operation firstOperation = compute.create(AddressInfo.of(firstAddressId)); + Operation secondOperation = compute.create(AddressInfo.of(secondAddressId)); + while (!firstOperation.isDone()) { + Thread.sleep(1000L); + } + while (!secondOperation.isDone()) { + Thread.sleep(1000L); + } + Set addressSet = ImmutableSet.copyOf(addressNames); + // test list + Compute.AddressFilter filter = + Compute.AddressFilter.equals(Compute.AddressField.NAME, prefix + "\\d"); + Page
addressPage = + compute.listGlobalAddresses(Compute.AddressListOption.filter(filter)); + Iterator
addressIterator = addressPage.iterateAll(); + int count = 0; + while (addressIterator.hasNext()) { + Address address = addressIterator.next(); + assertNotNull(address.addressId()); + assertTrue(address.addressId() instanceof GlobalAddressId); + assertTrue(addressSet.contains(address.addressId().address())); + assertNotNull(address.address()); + assertNotNull(address.creationTimestamp()); + assertNotNull(address.id()); + count++; + } + assertEquals(2, count); + // test list with selected fields + count = 0; + addressPage = compute.listGlobalAddresses(Compute.AddressListOption.filter(filter), + Compute.AddressListOption.fields(Compute.AddressField.ADDRESS)); + addressIterator = addressPage.iterateAll(); + while (addressIterator.hasNext()) { + Address address = addressIterator.next(); + assertTrue(address.addressId() instanceof GlobalAddressId); + assertTrue(addressSet.contains(address.addressId().address())); + assertNotNull(address.address()); + assertNull(address.creationTimestamp()); + assertNull(address.id()); + assertNull(address.status()); + assertNull(address.usage()); + count++; + } + assertEquals(2, count); + compute.delete(firstAddressId); + compute.delete(secondAddressId); + } }