From 741b80404204bb8936c4b95e9e9e43ea5b0722da Mon Sep 17 00:00:00 2001 From: Marco Ziccardi Date: Tue, 22 Mar 2016 16:29:47 +0100 Subject: [PATCH 1/2] Add SnapshotInfo, related classes and tests --- .../com/google/gcloud/compute/DiskId.java | 162 ++++++ .../com/google/gcloud/compute/SnapshotId.java | 132 +++++ .../google/gcloud/compute/SnapshotInfo.java | 484 ++++++++++++++++++ .../com/google/gcloud/compute/DiskIdTest.java | 87 ++++ .../google/gcloud/compute/SnapshotIdTest.java | 79 +++ .../gcloud/compute/SnapshotInfoTest.java | 135 +++++ 6 files changed, 1079 insertions(+) create mode 100644 gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java create mode 100644 gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotId.java create mode 100644 gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java create mode 100644 gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskIdTest.java create mode 100644 gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java create mode 100644 gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotInfoTest.java diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java new file mode 100644 index 000000000000..b2a0f3e45db7 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java @@ -0,0 +1,162 @@ +/* + * 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 disk. + */ +public final class DiskId extends ResourceId { + + private static final String REGEX = ResourceId.REGEX + "zones/([^/]+)/disks/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + private static final long serialVersionUID = -8761290740495870787L; + + private final String zone; + private final String disk; + + private DiskId(String project, String zone, String disk) { + super(project); + this.zone = checkNotNull(zone); + this.disk = checkNotNull(disk); + } + + /** + * Returns the name of the zone this disk belongs to. + */ + public String zone() { + return zone; + } + + /** + * Returns the identity of the zone this disk belongs to. + */ + public ZoneId zoneId() { + return ZoneId.of(project(), zone); + } + + /** + * Returns the name of the disk. 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 disk() { + return disk; + } + + @Override + public String selfLink() { + return super.selfLink() + "/zones/" + zone + "/disks/" + disk; + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("zone", zone).add("disk", disk); + } + + @Override + public int hashCode() { + return Objects.hash(super.baseHashCode(), zone, disk); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof DiskId)) { + return false; + } + DiskId other = (DiskId) obj; + return baseEquals(other) + && Objects.equals(zone, other.zone) + && Objects.equals(disk, other.disk); + } + + @Override + DiskId setProjectId(String projectId) { + if (project() != null) { + return this; + } + return DiskId.of(projectId, zone, disk); + } + + /** + * Returns a disk identity given the zone identity and the disk 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 DiskId of(ZoneId zoneId, String disk) { + return new DiskId(zoneId.project(), zoneId.zone(), disk); + } + + /** + * Returns a disk identity given the zone and disk 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 DiskId of(String zone, String disk) { + return new DiskId(null, zone, disk); + } + + /** + * Returns a disk identity given project, zone and disks 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 DiskId of(String project, String zone, String disk) { + return new DiskId(project, zone, disk); + } + + /** + * Returns {@code true} if the provided string matches the expected format of a disk URL. Returns + * {@code false} otherwise. + */ + static boolean matchesUrl(String url) { + return PATTERN.matcher(url).matches(); + } + + static DiskId fromUrl(String url) { + Matcher matcher = PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException(url + " is not a valid disk URL"); + } + return DiskId.of(matcher.group(1), matcher.group(2), matcher.group(3)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotId.java new file mode 100644 index 000000000000..5df2d9f0f9a8 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotId.java @@ -0,0 +1,132 @@ +/* + * 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 snapshot. + */ +public final class SnapshotId extends ResourceId { + + private static final String REGEX = ResourceId.REGEX + "global/snapshots/([^/]+)"; + private static final Pattern PATTERN = Pattern.compile(REGEX); + private static final long serialVersionUID = -1699492866663041082L; + + private final String snapshot; + + private SnapshotId(String project, String snapshot) { + super(project); + this.snapshot = checkNotNull(snapshot); + } + + /** + * Returns the name of the snapshot. 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 snapshot() { + return snapshot; + } + + @Override + public String selfLink() { + return super.selfLink() + "/global/snapshots/" + snapshot; + } + + @Override + MoreObjects.ToStringHelper toStringHelper() { + return super.toStringHelper().add("snapshot", snapshot); + } + + @Override + public int hashCode() { + return Objects.hash(baseHashCode(), snapshot); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof SnapshotId)) { + return false; + } + SnapshotId other = (SnapshotId) obj; + return baseEquals(other) && Objects.equals(snapshot, other.snapshot); + } + + @Override + SnapshotId setProjectId(String projectId) { + if (project() != null) { + return this; + } + return SnapshotId.of(projectId, snapshot); + } + + /** + * Returns a snapshot identity given the snapshot name. The snapshot 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 SnapshotId of(String snapshot) { + return new SnapshotId(null, snapshot); + } + + /** + * Returns a snapshot identity given project and snapshot names. The snapshot 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 SnapshotId of(String project, String snapshot) { + return new SnapshotId(project, snapshot); + } + + /** + * Returns {@code true} if the provided string matches the expected format of a snapshot URL. + * Returns {@code false} otherwise. + */ + static boolean matchesUrl(String url) { + return url.matches(REGEX); + } + + static SnapshotId fromUrl(String url) { + Matcher matcher = PATTERN.matcher(url); + if (!matcher.matches()) { + throw new IllegalArgumentException(url + " is not a valid snapshot URL"); + } + return SnapshotId.of(matcher.group(1), matcher.group(2)); + } +} diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java new file mode 100644 index 000000000000..283ca665d173 --- /dev/null +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java @@ -0,0 +1,484 @@ +/* + * 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.Snapshot; +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 snapshot. Compute Engine allows you to take snapshots of your persistent + * disk and create new persistent disks from that snapshot. This can be useful for backing up data, + * recreating a persistent disk that might have been lost, or copying a persistent disk. Snapshots + * can be applied across persistent disk types. + * + * @see Use + * persistent disk snapshots + */ +public class SnapshotInfo implements Serializable { + + static final Function FROM_PB_FUNCTION = + new Function() { + @Override + public SnapshotInfo apply(Snapshot pb) { + return SnapshotInfo.fromPb(pb); + } + }; + static final Function TO_PB_FUNCTION = + new Function() { + @Override + public Snapshot apply(SnapshotInfo snapshot) { + return snapshot.toPb(); + } + }; + + private static final long serialVersionUID = 1065513502131159769L; + private static final DateTimeFormatter TIMESTAMP_FORMATTER = ISODateTimeFormat.dateTime(); + + private final String id; + private final SnapshotId snapshotId; + private final Long creationTimestamp; + private final String description; + private final Status status; + private final Long diskSizeGb; + private final List licenses; + private final DiskId sourceDisk; + private final String sourceDiskId; + private final Long storageBytes; + private final StorageBytesStatus storageBytesStatus; + + /** + * The status of a Google Compute Engine snapshot. A snapshot can be used to create other + * resources, such as disks, only after the snapshot has been successfully created and the status + * is set to {@code READY}. + */ + public enum Status { + /** + * The snapshot is being created. + */ + CREATING, + + /** + * The snapshot is being deleted. + */ + DELETING, + + /** + * Snapshot's creation failed. + */ + FAILED, + + /** + * Snapshot has been successfully created. + */ + READY, + + /** + * Snapshot is being uploaded. + */ + UPLOADING + } + + /** + * An indicator whether {@link SnapshotInfo#storageBytes()} is in a stable state or it is being + * adjusted as a result of shared storage reallocation. + */ + public enum StorageBytesStatus { + /** + * Indicates that the size of the snapshot is being updated. + */ + UPDATING, + + /** + * Indicates that the size of the snapshot is up-to-date. + */ + UP_TO_DATE + } + + /** + * A builder for {@code SnapshotInfo} objects. + */ + public abstract static class Builder { + + abstract Builder id(String id); + + abstract Builder creationTimestamp(Long creationTimestamp); + + /** + * Sets the snapshot identity. + */ + public abstract Builder snapshotId(SnapshotId snapshotId); + + /** + * Sets an optional textual description of the snapshot. + */ + public abstract Builder description(String description); + + abstract Builder status(Status status); + + abstract Builder diskSizeGb(Long diskSizeGb); + + abstract Builder licenses(List licenses); + + /** + * Sets the identity of the source disk used to create the snapshot. + */ + public abstract Builder sourceDisk(DiskId sourceDisk); + + abstract Builder sourceDiskId(String sourceDiskId); + + abstract Builder storageBytes(Long storageBytes); + + abstract Builder storageBytesStatus(StorageBytesStatus storageBytesStatus); + + /** + * Creates a {@code SnapshotInfo} object. + */ + public abstract SnapshotInfo build(); + } + + static final class BuilderImpl extends Builder { + + private String id; + private Long creationTimestamp; + private SnapshotId snapshotId; + private String description; + private Status status; + private Long diskSizeGb; + private List licenses; + private DiskId sourceDisk; + private String sourceDiskId; + private Long storageBytes; + private StorageBytesStatus storageBytesStatus; + + BuilderImpl() {} + + BuilderImpl(SnapshotInfo snapshotInfo) { + this.id = snapshotInfo.id; + this.creationTimestamp = snapshotInfo.creationTimestamp; + this.snapshotId = snapshotInfo.snapshotId; + this.description = snapshotInfo.description; + this.status = snapshotInfo.status; + this.diskSizeGb = snapshotInfo.diskSizeGb; + this.licenses = snapshotInfo.licenses; + this.sourceDisk = snapshotInfo.sourceDisk; + this.sourceDiskId = snapshotInfo.sourceDiskId; + this.storageBytes = snapshotInfo.storageBytes; + this.storageBytesStatus = snapshotInfo.storageBytesStatus; + } + + BuilderImpl(Snapshot snapshotPb) { + if (snapshotPb.getId() != null) { + this.id = snapshotPb.getId().toString(); + } + if (snapshotPb.getCreationTimestamp() != null) { + this.creationTimestamp = TIMESTAMP_FORMATTER.parseMillis(snapshotPb.getCreationTimestamp()); + } + this.snapshotId = SnapshotId.fromUrl(snapshotPb.getSelfLink()); + this.description = snapshotPb.getDescription(); + if (snapshotPb.getStatus() != null) { + this.status = Status.valueOf(snapshotPb.getStatus()); + } + this.diskSizeGb = snapshotPb.getDiskSizeGb(); + if (snapshotPb.getLicenses() != null) { + this.licenses = Lists.transform(snapshotPb.getLicenses(), LicenseId.FROM_URL_FUNCTION); + } + if (snapshotPb.getSourceDisk() != null) { + this.sourceDisk = DiskId.fromUrl(snapshotPb.getSourceDisk()); + } + this.sourceDiskId = snapshotPb.getSourceDiskId(); + this.storageBytes = snapshotPb.getStorageBytes(); + if (snapshotPb.getStorageBytesStatus() != null) { + this.storageBytesStatus = StorageBytesStatus.valueOf(snapshotPb.getStorageBytesStatus()); + } + } + + @Override + BuilderImpl id(String id) { + this.id = id; + return this; + } + + @Override + BuilderImpl creationTimestamp(Long creationTimestamp) { + this.creationTimestamp = creationTimestamp; + return this; + } + + @Override + public BuilderImpl snapshotId(SnapshotId snapshotId) { + this.snapshotId = checkNotNull(snapshotId); + return this; + } + + @Override + public BuilderImpl description(String description) { + this.description = description; + return this; + } + + @Override + BuilderImpl status(Status status) { + this.status = status; + return this; + } + + @Override + BuilderImpl diskSizeGb(Long diskSizeGb) { + this.diskSizeGb = diskSizeGb; + return this; + } + + @Override + BuilderImpl licenses(List licenses) { + this.licenses = licenses != null ? ImmutableList.copyOf(licenses) : null; + return this; + } + + @Override + public BuilderImpl sourceDisk(DiskId sourceDisk) { + this.sourceDisk = checkNotNull(sourceDisk); + return this; + } + + @Override + BuilderImpl sourceDiskId(String sourceDiskId) { + this.sourceDiskId = sourceDiskId; + return this; + } + + @Override + BuilderImpl storageBytes(Long storageBytes) { + this.storageBytes = storageBytes; + return this; + } + + @Override + BuilderImpl storageBytesStatus(StorageBytesStatus storageBytesStatus) { + this.storageBytesStatus = storageBytesStatus; + return this; + } + + @Override + public SnapshotInfo build() { + return new SnapshotInfo(this); + } + } + + SnapshotInfo(BuilderImpl builder) { + this.id = builder.id; + this.creationTimestamp = builder.creationTimestamp; + this.snapshotId = checkNotNull(builder.snapshotId); + this.description = builder.description; + this.status = builder.status; + this.diskSizeGb = builder.diskSizeGb; + this.licenses = builder.licenses; + this.sourceDisk = builder.sourceDisk; + this.sourceDiskId = builder.sourceDiskId; + this.storageBytes = builder.storageBytes; + this.storageBytesStatus = builder.storageBytesStatus; + } + + /** + * Returns the unique identifier for the snapshot; defined by the service. + */ + public String id() { + return id; + } + + /** + * Returns the creation timestamp in milliseconds since epoch. + */ + public Long creationTimestamp() { + return creationTimestamp; + } + + /** + * Returns the snapshot identity. + */ + public SnapshotId snapshotId() { + return snapshotId; + } + + /** + * Returns a textual description of the snapshot. + */ + public String description() { + return description; + } + + /** + * Returns all applicable publicly visible licenses. + */ + public List licenses() { + return licenses; + } + + /** + * Returns the status of the snapshot. A snapshot can be used to create other resources, such as + * disks, only after the snapshot has been successfully created and the status is set to + * {@code READY}. + */ + public Status status() { + return status; + } + + /** + * Returns the size of the snapshot (in GB). + */ + public Long diskSizeGb() { + return diskSizeGb; + } + + /** + * Returns the identity of the source disk used to create this snapshot. + */ + public DiskId sourceDisk() { + return sourceDisk; + } + + /** + * Returns the id value of the disk used to create this snapshot. This value may be used to + * determine whether the snapshot was taken from the current or a previous instance of a given + * disk name. + */ + public String sourceDiskId() { + return sourceDiskId; + } + + /** + * Returns the size of the the storage used by the snapshot. As snapshots share storage, this + * number is expected to change with snapshot creation/deletion. + */ + public Long storageBytes() { + return storageBytes; + } + + /** + * Indicates whether {@link SnapshotInfo#storageBytes()} is in a stable state or it is being + * adjusted as a result of shared storage reallocation. {@link StorageBytesStatus#UPDATING} + * indicates that the size of the snapshot is being updated. {@link StorageBytesStatus#UP_TO_DATE} + * indicates that the size of the snapshot is up-to-date. + */ + public StorageBytesStatus storageBytesStatus() { + return storageBytesStatus; + } + + /** + * Returns a builder for the current snapshot. + */ + public Builder toBuilder() { + return new BuilderImpl(this); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("id", id) + .add("creationTimestamp", creationTimestamp) + .add("snapshotId", snapshotId) + .add("description", description) + .add("status", status) + .add("diskSizeGb", diskSizeGb) + .add("licenses", licenses) + .add("sourceDisk", sourceDisk) + .add("sourceDiskId", sourceDiskId) + .add("storageBytes", storageBytes) + .add("storageBytesStatus", storageBytesStatus) + .toString(); + } + + @Override + public int hashCode() { + return Objects.hash(id, creationTimestamp, snapshotId, description, status, diskSizeGb, + licenses, sourceDisk, sourceDiskId, storageBytes, storageBytesStatus); + } + + @Override + public boolean equals(Object obj) { + return obj != null + && obj.getClass().equals(SnapshotInfo.class) + && Objects.equals(toPb(), ((SnapshotInfo) obj).toPb()); + } + + SnapshotInfo setProjectId(String projectId) { + return toBuilder() + .snapshotId(snapshotId.setProjectId(projectId)) + .sourceDisk(sourceDisk.setProjectId(projectId)) + .build(); + } + + Snapshot toPb() { + Snapshot snapshotPb = new Snapshot(); + if (id != null) { + snapshotPb.setId(new BigInteger(id)); + } + if (creationTimestamp != null) { + snapshotPb.setCreationTimestamp(TIMESTAMP_FORMATTER.print(creationTimestamp)); + } + snapshotPb.setName(snapshotId.snapshot()); + snapshotPb.setDescription(description); + snapshotPb.setSelfLink(snapshotId.selfLink()); + if (status != null) { + snapshotPb.setStatus(status.name()); + } + snapshotPb.setDiskSizeGb(diskSizeGb); + if (licenses != null) { + snapshotPb.setLicenses(Lists.transform(licenses, LicenseId.TO_URL_FUNCTION)); + } + if (sourceDisk != null) { + snapshotPb.setSourceDisk(sourceDisk.selfLink()); + } + snapshotPb.setSourceDiskId(sourceDiskId); + snapshotPb.setStorageBytes(storageBytes); + if (storageBytesStatus != null) { + snapshotPb.setStorageBytesStatus(storageBytesStatus.name()); + } + return snapshotPb; + } + + /** + * Returns a builder for a {@code SnapshotInfo} object given the snapshot identity and a source + * disk identity. + */ + public static Builder builder(SnapshotId snapshotId, DiskId source) { + return new BuilderImpl().snapshotId(snapshotId).sourceDisk(source); + } + + /** + * Returns a {@code SnapshotInfo} object given the snapshot identity and a source disk identity. + */ + public static SnapshotInfo of(SnapshotId snapshotId, DiskId source) { + return builder(snapshotId, source).build(); + } + + static SnapshotInfo fromPb(Snapshot snapshotPb) { + return new BuilderImpl(snapshotPb).build(); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskIdTest.java new file mode 100644 index 000000000000..216f3237f8a5 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/DiskIdTest.java @@ -0,0 +1,87 @@ +/* + * 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 DiskIdTest { + + private static final String PROJECT = "project"; + private static final String ZONE = "zone"; + private static final String NAME = "disk"; + private static final String URL = + "https://www.googleapis.com/compute/v1/projects/project/zones/zone/disks/disk"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testOf() { + DiskId diskId = DiskId.of(PROJECT, ZONE, NAME); + assertEquals(PROJECT, diskId.project()); + assertEquals(ZONE, diskId.zone()); + assertEquals(NAME, diskId.disk()); + assertEquals(URL, diskId.selfLink()); + diskId = DiskId.of(ZONE, NAME); + assertNull(diskId.project()); + assertEquals(ZONE, diskId.zone()); + assertEquals(NAME, diskId.disk()); + diskId = DiskId.of(ZoneId.of(ZONE), NAME); + assertNull(diskId.project()); + assertEquals(ZONE, diskId.zone()); + assertEquals(NAME, diskId.disk()); + } + + @Test + public void testToAndFromUrl() { + DiskId diskId = DiskId.of(PROJECT, ZONE, NAME); + compareDiskId(diskId, DiskId.fromUrl(diskId.selfLink())); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("notMatchingUrl is not a valid disk URL"); + DiskId.fromUrl("notMatchingUrl"); + } + + @Test + public void testSetProjectId() { + DiskId diskId = DiskId.of(PROJECT, ZONE, NAME); + assertSame(diskId, diskId.setProjectId(PROJECT)); + compareDiskId(diskId, DiskId.of(ZONE, NAME).setProjectId(PROJECT)); + } + + @Test + public void testMatchesUrl() { + assertTrue(DiskId.matchesUrl(DiskId.of(PROJECT, ZONE, NAME).selfLink())); + assertFalse(DiskId.matchesUrl("notMatchingUrl")); + } + + private void compareDiskId(DiskId expected, DiskId value) { + assertEquals(expected, value); + assertEquals(expected.project(), expected.project()); + assertEquals(expected.zone(), expected.zone()); + assertEquals(expected.disk(), expected.disk()); + assertEquals(expected.selfLink(), expected.selfLink()); + assertEquals(expected.hashCode(), expected.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java new file mode 100644 index 000000000000..cbda6fd3ebd0 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java @@ -0,0 +1,79 @@ +/* + * 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 SnapshotIdTest { + + private static final String PROJECT = "project"; + private static final String NAME = "snapshot"; + private static final String URL = + "https://www.googleapis.com/compute/v1/projects/project/global/snapshots/snapshot"; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testOf() { + SnapshotId snapshotId = SnapshotId.of(PROJECT, NAME); + assertEquals(PROJECT, snapshotId.project()); + assertEquals(NAME, snapshotId.snapshot()); + assertEquals(URL, snapshotId.selfLink()); + snapshotId = SnapshotId.of(NAME); + assertNull(snapshotId.project()); + assertEquals(NAME, snapshotId.snapshot()); + } + + @Test + public void testToAndFromUrl() { + SnapshotId snapshotId = SnapshotId.of(PROJECT, NAME); + compareSnapshotId(snapshotId, SnapshotId.fromUrl(snapshotId.selfLink())); + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("notMatchingUrl is not a valid snapshot URL"); + SnapshotId.fromUrl("notMatchingUrl"); + } + + @Test + public void testSetProjectId() { + SnapshotId snapshotId = SnapshotId.of(PROJECT, NAME); + assertSame(snapshotId, snapshotId.setProjectId(PROJECT)); + compareSnapshotId(snapshotId, SnapshotId.of(NAME).setProjectId(PROJECT)); + } + + @Test + public void testMatchesUrl() { + assertTrue(GlobalOperationId.matchesUrl(GlobalOperationId.of(PROJECT, NAME).selfLink())); + assertFalse(GlobalOperationId.matchesUrl("notMatchingUrl")); + } + + private void compareSnapshotId(SnapshotId expected, SnapshotId value) { + assertEquals(expected, value); + assertEquals(expected.project(), expected.project()); + assertEquals(expected.snapshot(), expected.snapshot()); + assertEquals(expected.selfLink(), expected.selfLink()); + assertEquals(expected.hashCode(), expected.hashCode()); + } +} diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotInfoTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotInfoTest.java new file mode 100644 index 000000000000..15789b414574 --- /dev/null +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotInfoTest.java @@ -0,0 +1,135 @@ +/* + * 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.SnapshotInfo.Status; +import com.google.gcloud.compute.SnapshotInfo.StorageBytesStatus; + +import org.junit.Test; + +import java.util.List; + +public class SnapshotInfoTest { + + private static final String ID = "42"; + private static final DiskId SOURCE_DISK = DiskId.of("project", "zone", "disk"); + private static final Long CREATION_TIMESTAMP = 1453293540000L; + private static final String DESCRIPTION = "description"; + private static final List LICENSES = ImmutableList.of( + LicenseId.of("project", "license1"), LicenseId.of("project", "license2")); + private static final SnapshotId SNAPSHOT_ID = SnapshotId.of("project", "snapshot"); + private static final Status STATUS = Status.CREATING; + private static final Long DISK_SIZE_GB = 42L; + private static final String SOURCE_DISK_ID = "diskId"; + private static final Long STORAGE_BYTES = 24L; + private static final StorageBytesStatus STORAGE_BYTES_STATUS = StorageBytesStatus.UP_TO_DATE; + private static final SnapshotInfo SNAPSHOT_INFO = SnapshotInfo.builder(SNAPSHOT_ID, SOURCE_DISK) + .id(ID) + .creationTimestamp(CREATION_TIMESTAMP) + .description(DESCRIPTION) + .status(STATUS) + .diskSizeGb(DISK_SIZE_GB) + .licenses(LICENSES) + .sourceDiskId(SOURCE_DISK_ID) + .storageBytes(STORAGE_BYTES) + .storageBytesStatus(STORAGE_BYTES_STATUS) + .build(); + + @Test + public void testToBuilder() { + compareSnapshotInfo(SNAPSHOT_INFO, SNAPSHOT_INFO.toBuilder().build()); + SnapshotInfo snapshotInfo = SNAPSHOT_INFO.toBuilder().description("newDescription").build(); + assertEquals("newDescription", snapshotInfo.description()); + snapshotInfo = snapshotInfo.toBuilder().description("description").build(); + compareSnapshotInfo(SNAPSHOT_INFO, snapshotInfo); + } + + @Test + public void testToBuilderIncomplete() { + SnapshotInfo snapshotInfo = SnapshotInfo.of(SNAPSHOT_ID, SOURCE_DISK); + assertEquals(snapshotInfo, snapshotInfo.toBuilder().build()); + } + + @Test + public void testBuilder() { + assertEquals(ID, SNAPSHOT_INFO.id()); + assertEquals(SNAPSHOT_ID, SNAPSHOT_INFO.snapshotId()); + assertEquals(CREATION_TIMESTAMP, SNAPSHOT_INFO.creationTimestamp()); + assertEquals(DESCRIPTION, SNAPSHOT_INFO.description()); + assertEquals(STATUS, SNAPSHOT_INFO.status()); + assertEquals(DISK_SIZE_GB, SNAPSHOT_INFO.diskSizeGb()); + assertEquals(LICENSES, SNAPSHOT_INFO.licenses()); + assertEquals(SOURCE_DISK, SNAPSHOT_INFO.sourceDisk()); + assertEquals(SOURCE_DISK_ID, SNAPSHOT_INFO.sourceDiskId()); + assertEquals(STORAGE_BYTES, SNAPSHOT_INFO.storageBytes()); + assertEquals(STORAGE_BYTES_STATUS, SNAPSHOT_INFO.storageBytesStatus()); + } + + @Test + public void testOf() { + SnapshotInfo snapshotInfo = SnapshotInfo.of(SNAPSHOT_ID, SOURCE_DISK); + assertNull(snapshotInfo.id()); + assertEquals(SNAPSHOT_ID, snapshotInfo.snapshotId()); + assertNull(snapshotInfo.creationTimestamp()); + assertNull(snapshotInfo.description()); + assertNull(snapshotInfo.status()); + assertNull(snapshotInfo.diskSizeGb()); + assertNull(snapshotInfo.licenses()); + assertEquals(SOURCE_DISK, snapshotInfo.sourceDisk()); + assertNull(snapshotInfo.sourceDiskId()); + assertNull(snapshotInfo.storageBytes()); + assertNull(snapshotInfo.storageBytesStatus()); + } + + @Test + public void testToAndFromPb() { + compareSnapshotInfo(SNAPSHOT_INFO, SnapshotInfo.fromPb(SNAPSHOT_INFO.toPb())); + SnapshotInfo snapshotInfo = SnapshotInfo.of(SNAPSHOT_ID, SOURCE_DISK); + compareSnapshotInfo(snapshotInfo, SnapshotInfo.fromPb(snapshotInfo.toPb())); + snapshotInfo = new SnapshotInfo.BuilderImpl().snapshotId(SNAPSHOT_ID).build(); + compareSnapshotInfo(snapshotInfo, SnapshotInfo.fromPb(snapshotInfo.toPb())); + } + + @Test + public void testSetProjectId() { + SnapshotInfo snapshotInfo = SNAPSHOT_INFO.toBuilder() + .snapshotId(SnapshotId.of("snapshot")) + .sourceDisk(DiskId.of("zone", "disk")) + .build(); + compareSnapshotInfo(SNAPSHOT_INFO, snapshotInfo.setProjectId("project")); + } + + public void compareSnapshotInfo(SnapshotInfo expected, SnapshotInfo value) { + assertEquals(expected, value); + assertEquals(expected.id(), value.id()); + assertEquals(expected.snapshotId(), value.snapshotId()); + assertEquals(expected.creationTimestamp(), value.creationTimestamp()); + assertEquals(expected.description(), value.description()); + assertEquals(expected.status(), value.status()); + assertEquals(expected.diskSizeGb(), value.diskSizeGb()); + assertEquals(expected.licenses(), value.licenses()); + assertEquals(expected.sourceDisk(), value.sourceDisk()); + assertEquals(expected.sourceDiskId(), value.sourceDiskId()); + assertEquals(expected.storageBytes(), value.storageBytes()); + assertEquals(expected.storageBytesStatus(), value.storageBytesStatus()); + assertEquals(expected.hashCode(), value.hashCode()); + } +} From f968d386eb8e8da983ca2414e3a994fe76616220 Mon Sep 17 00:00:00 2001 From: Marco Ziccardi Date: Wed, 23 Mar 2016 17:10:21 +0100 Subject: [PATCH 2/2] Add SnapshotInfo and related classes to SerializationTest, minor fixes --- .../java/com/google/gcloud/compute/DiskId.java | 8 ++++---- .../com/google/gcloud/compute/SnapshotInfo.java | 7 +++---- .../google/gcloud/compute/SerializationTest.java | 14 +++++++++----- .../com/google/gcloud/compute/SnapshotIdTest.java | 4 ++-- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java index b2a0f3e45db7..7338e04ef5d8 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/DiskId.java @@ -106,8 +106,8 @@ DiskId setProjectId(String projectId) { } /** - * Returns a disk identity given the zone identity and the disk name. The address name must be - * 1-63 characters long and comply with RFC1035. Specifically, the name must match the regular + * Returns a disk identity given the zone identity and the disk name. The disk 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. @@ -119,7 +119,7 @@ public static DiskId of(ZoneId zoneId, String disk) { } /** - * Returns a disk identity given the zone and disk names. The address name must be 1-63 characters + * Returns a disk identity given the zone and disk names. The disk 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 @@ -132,7 +132,7 @@ public static DiskId of(String zone, String disk) { } /** - * Returns a disk identity given project, zone and disks names. The address name must be 1-63 + * Returns a disk identity given project, zone and disks names. The disk 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, diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java index 283ca665d173..fe567988d82c 100644 --- a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java +++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SnapshotInfo.java @@ -74,9 +74,8 @@ public Snapshot apply(SnapshotInfo snapshot) { private final StorageBytesStatus storageBytesStatus; /** - * The status of a Google Compute Engine snapshot. A snapshot can be used to create other - * resources, such as disks, only after the snapshot has been successfully created and the status - * is set to {@code READY}. + * The status of a Google Compute Engine snapshot. A snapshot can be used to create a disk only + * after the snapshot has been successfully created and the status is set to {@code READY}. */ public enum Status { /** @@ -106,7 +105,7 @@ public enum Status { } /** - * An indicator whether {@link SnapshotInfo#storageBytes()} is in a stable state or it is being + * An indicator of whether {@link SnapshotInfo#storageBytes()} is in a stable state or it is being * adjusted as a result of shared storage reallocation. */ public enum StorageBytesStatus { 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 81afee4acf50..8b5956cef100 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 @@ -147,6 +147,9 @@ public class SerializationTest { .usage(INSTANCE_USAGE) .build(); private static final Address ADDRESS = new Address.Builder(COMPUTE, REGION_ADDRESS_ID).build(); + private static final DiskId DISK_ID = DiskId.of("project", "zone", "disk"); + private static final SnapshotId SNAPSHOT_ID = SnapshotId.of("project", "snapshot"); + private static final SnapshotInfo SNAPSHOT_INFO = SnapshotInfo.of(SNAPSHOT_ID, DISK_ID); private static final Compute.DiskTypeOption DISK_TYPE_OPTION = Compute.DiskTypeOption.fields(); private static final Compute.DiskTypeFilter DISK_TYPE_FILTER = @@ -212,11 +215,12 @@ public void testModelAndRequests() throws Exception { REGION_OPERATION_ID, ZONE_OPERATION_ID, GLOBAL_OPERATION, REGION_OPERATION, ZONE_OPERATION, 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_INFO, ADDRESS, DISK_ID, SNAPSHOT_ID, SNAPSHOT_INFO, 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); diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java index cbda6fd3ebd0..13dadee790b9 100644 --- a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java +++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SnapshotIdTest.java @@ -65,8 +65,8 @@ public void testSetProjectId() { @Test public void testMatchesUrl() { - assertTrue(GlobalOperationId.matchesUrl(GlobalOperationId.of(PROJECT, NAME).selfLink())); - assertFalse(GlobalOperationId.matchesUrl("notMatchingUrl")); + assertTrue(SnapshotId.matchesUrl(SnapshotId.of(PROJECT, NAME).selfLink())); + assertFalse(SnapshotId.matchesUrl("notMatchingUrl")); } private void compareSnapshotId(SnapshotId expected, SnapshotId value) {