diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/NetworkId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/NetworkId.java
new file mode 100644
index 000000000000..09bf05fb6b9c
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/NetworkId.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Identity for a Google Compute Engine network.
+ */
+public final class NetworkId extends ResourceId {
+
+ private static final String REGEX = ResourceId.REGEX + "global/networks/([^/]+)";
+ private static final Pattern PATTERN = Pattern.compile(REGEX);
+ private static final long serialVersionUID = 2386765228138819506L;
+
+ private final String network;
+
+ NetworkId(String project, String network) {
+ super(project);
+ this.network = checkNotNull(network);
+ }
+
+ private NetworkId(NetworkId networkId) {
+ super(networkId.project());
+ this.network = checkNotNull(networkId.network());
+ }
+
+ /**
+ * Returns the name of the network. The network 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 network() {
+ return network;
+ }
+
+ @Override
+ public String selfLink() {
+ return super.selfLink() + "/global/networks/" + network;
+ }
+
+ @Override
+ ToStringHelper toStringHelper() {
+ return super.toStringHelper().add("network", network);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(baseHashCode(), network);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof NetworkId)) {
+ return false;
+ }
+ NetworkId other = (NetworkId) obj;
+ return baseEquals(other) && Objects.equals(network, other.network);
+ }
+
+ @Override
+ NetworkId setProjectId(String projectId) {
+ if (project() != null) {
+ return this;
+ }
+ return NetworkId.of(projectId, network);
+ }
+
+ /**
+ * Returns a new network identity given project and network names. The network 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 NetworkId of(String project, String network) {
+ return new NetworkId(project, network);
+ }
+
+ /**
+ * Returns a new network identity given network name. The network 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 NetworkId of(String network) {
+ return NetworkId.of(null, network);
+ }
+
+ /**
+ * Returns {@code true} if the provided string matches the expected format of a network URL.
+ * Returns {@code false} otherwise.
+ */
+ static boolean matchesUrl(String url) {
+ return PATTERN.matcher(url).matches();
+ }
+
+ static NetworkId fromUrl(String url) {
+ Matcher matcher = PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(url + " is not a valid network URL");
+ }
+ return NetworkId.of(matcher.group(1), matcher.group(2));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkId.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkId.java
new file mode 100644
index 000000000000..7ed56f4ba3cf
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkId.java
@@ -0,0 +1,179 @@
+/*
+ * 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 subnetwork.
+ */
+public final class SubnetworkId extends ResourceId {
+
+ static final Function FROM_URL_FUNCTION =
+ new Function() {
+ @Override
+ public SubnetworkId apply(String pb) {
+ return SubnetworkId.fromUrl(pb);
+ }
+ };
+ static final Function TO_URL_FUNCTION =
+ new Function() {
+ @Override
+ public String apply(SubnetworkId zoneId) {
+ return zoneId.selfLink();
+ }
+ };
+
+ private static final String REGEX = ResourceId.REGEX + "regions/([^/]+)/subnetworks/([^/]+)";
+ private static final Pattern PATTERN = Pattern.compile(REGEX);
+ private static final long serialVersionUID = -5451054513760540282L;
+
+ private final String region;
+ private final String subnetwork;
+
+ private SubnetworkId(String project, String region, String subnetwork) {
+ super(project);
+ this.region = checkNotNull(region);
+ this.subnetwork = checkNotNull(subnetwork);
+ }
+
+ /**
+ * Returns the name of the region this subnetwork belongs to.
+ */
+ public String region() {
+ return region;
+ }
+
+ /**
+ * Returns the identity of the region this subnetwork belongs to.
+ */
+ public RegionId regionId() {
+ return RegionId.of(project(), region);
+ }
+
+ /**
+ * Returns the name of the subnetwork. 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 subnetwork() {
+ return subnetwork;
+ }
+
+ @Override
+ public String selfLink() {
+ return super.selfLink() + "/regions/" + region + "/subnetworks/" + subnetwork;
+ }
+
+ @Override
+ MoreObjects.ToStringHelper toStringHelper() {
+ return MoreObjects.toStringHelper(this).add("region", region).add("subnetwork", subnetwork);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(baseHashCode(), region, subnetwork);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof SubnetworkId)) {
+ return false;
+ }
+ SubnetworkId other = (SubnetworkId) obj;
+ return baseEquals(other)
+ && Objects.equals(region, other.region)
+ && Objects.equals(subnetwork, other.subnetwork);
+ }
+
+ @Override
+ SubnetworkId setProjectId(String projectId) {
+ if (project() != null) {
+ return this;
+ }
+ return SubnetworkId.of(projectId, region(), subnetwork);
+ }
+
+ /**
+ * Returns a subnetwork identity given the region identity and the subnetwork name. The subnetwork
+ * 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 SubnetworkId of(RegionId regionId, String subnetwork) {
+ return new SubnetworkId(regionId.project(), regionId.region(), subnetwork);
+ }
+
+ /**
+ * Returns a subnetwork identity given the region and subnetwork names. The subnetwork 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 SubnetworkId of(String region, String subnetwork) {
+ return new SubnetworkId(null, region, subnetwork);
+ }
+
+ /**
+ * Returns a subnetwork identity given project, region and subnetwork names. The subnetwork 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 SubnetworkId of(String project, String region, String subnetwork) {
+ return new SubnetworkId(project, region, subnetwork);
+ }
+
+ /**
+ * Returns {@code true} if the provided string matches the expected format of a subnetwork URL.
+ * Returns {@code false} otherwise.
+ */
+ static boolean matchesUrl(String url) {
+ return PATTERN.matcher(url).matches();
+ }
+
+ static SubnetworkId fromUrl(String url) {
+ Matcher matcher = PATTERN.matcher(url);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(url + " is not a valid subnetwork URL");
+ }
+ return SubnetworkId.of(matcher.group(1), matcher.group(2), matcher.group(3));
+ }
+}
diff --git a/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkInfo.java b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkInfo.java
new file mode 100644
index 000000000000..05eb0c95fc03
--- /dev/null
+++ b/gcloud-java-compute/src/main/java/com/google/gcloud/compute/SubnetworkInfo.java
@@ -0,0 +1,347 @@
+/*
+ * 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.Subnetwork;
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+
+import java.io.Serializable;
+import java.math.BigInteger;
+import java.util.Objects;
+
+/**
+ * A Google Compute Engine subnetwork. Compute Engine subnetworks allow you to segment your Compute
+ * Engine network IP space into subnetworks. Subnetworks for a Compute Engine network can be
+ * automatically allocated, or you can create a custom topology.
+ *
+ * @see Subnetworks
+ */
+public class SubnetworkInfo implements Serializable {
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public SubnetworkInfo apply(Subnetwork pb) {
+ return SubnetworkInfo.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public Subnetwork apply(SubnetworkInfo subnetwork) {
+ return subnetwork.toPb();
+ }
+ };
+
+ private static final long serialVersionUID = 7491176262675441579L;
+ private static final DateTimeFormatter TIMESTAMP_FORMATTER = ISODateTimeFormat.dateTime();
+
+ private final String id;
+ private final SubnetworkId subnetworkId;
+ private final Long creationTimestamp;
+ private final String description;
+ private final String gatewayAddress;
+ private final NetworkId network;
+ private final String ipRange;
+
+ /**
+ * A builder for {@code SubnetworkInfo} objects.
+ */
+ public static abstract class Builder {
+
+ abstract Builder id(String id);
+
+ abstract Builder creationTimestamp(Long creationTimestamp);
+
+ /**
+ * Sets the identity of the subnework.
+ */
+ public abstract Builder subnetworkId(SubnetworkId subnetworkId);
+
+ /**
+ * Sets an optional textual description of the subnetwork.
+ */
+ abstract public Builder description(String description);
+
+ abstract Builder gatewayAddress(String gatewayAddress);
+
+ /**
+ * Sets the identity of the network to which this subnetwork belongs. Only networks that are in
+ * subnet mode can have subnetworks.
+ */
+ abstract public Builder network(NetworkId network);
+
+ /**
+ * Sets the range of internal IPv4 addresses that are owned by this subnetwork. This range must
+ * be a CIDR specification, for example: {@code 192.168.0.0/16}. Ranges must be unique and
+ * non-overlapping within a network.
+ *
+ * @see CIDR
+ */
+ abstract public Builder ipRange(String ipRange);
+
+ /**
+ * Creates a {@code SubnetworkInfo} object.
+ */
+ abstract public SubnetworkInfo build();
+ }
+
+ static final class BuilderImpl extends Builder {
+
+ private String id;
+ private SubnetworkId subnetworkId;
+ private Long creationTimestamp;
+ private String description;
+ private String gatewayAddress;
+ private NetworkId network;
+ private String ipRange;
+
+ BuilderImpl(SubnetworkId subnetworkId, NetworkId network, String ipRange) {
+ this.subnetworkId = checkNotNull(subnetworkId);
+ this.network = checkNotNull(network);
+ this.ipRange = checkNotNull(ipRange);
+ }
+
+ BuilderImpl(SubnetworkInfo subnetworkInfo) {
+ this.id = subnetworkInfo.id;
+ this.creationTimestamp = subnetworkInfo.creationTimestamp;
+ this.subnetworkId = subnetworkInfo.subnetworkId;
+ this.description = subnetworkInfo.description;
+ this.gatewayAddress = subnetworkInfo.gatewayAddress;
+ this.network = subnetworkInfo.network;
+ this.ipRange = subnetworkInfo.ipRange;
+ }
+
+ BuilderImpl(Subnetwork subnetworkPb) {
+ if (subnetworkPb.getId() != null) {
+ this.id = subnetworkPb.getId().toString();
+ }
+ if (subnetworkPb.getCreationTimestamp() != null) {
+ this.creationTimestamp =
+ TIMESTAMP_FORMATTER.parseMillis(subnetworkPb.getCreationTimestamp());
+ }
+ this.subnetworkId = SubnetworkId.fromUrl(subnetworkPb.getSelfLink());
+ this.description = subnetworkPb.getDescription();
+ this.gatewayAddress = subnetworkPb.getGatewayAddress();
+ if (subnetworkPb.getNetwork() != null) {
+ this.network = NetworkId.fromUrl(subnetworkPb.getNetwork());
+ }
+ this.ipRange = subnetworkPb.getIpCidrRange();
+ }
+
+ @Override
+ BuilderImpl id(String id) {
+ this.id = id;
+ return this;
+ }
+
+ @Override
+ BuilderImpl creationTimestamp(Long creationTimestamp) {
+ this.creationTimestamp = creationTimestamp;
+ return this;
+ }
+
+ @Override
+ public BuilderImpl subnetworkId(SubnetworkId subnetworkId) {
+ this.subnetworkId = checkNotNull(subnetworkId);
+ return this;
+ }
+
+ @Override
+ public BuilderImpl description(String description) {
+ this.description = description;
+ return this;
+ }
+
+ @Override
+ BuilderImpl gatewayAddress(String gatewayAddress) {
+ this.gatewayAddress = gatewayAddress;
+ return this;
+ }
+
+ @Override
+ public BuilderImpl network(NetworkId network) {
+ this.network = checkNotNull(network);
+ return this;
+ }
+
+ @Override
+ public BuilderImpl ipRange(String ipRange) {
+ this.ipRange = checkNotNull(ipRange);
+ return this;
+ }
+
+ @Override
+ public SubnetworkInfo build() {
+ return new SubnetworkInfo(this);
+ }
+ }
+
+ SubnetworkInfo(BuilderImpl builder) {
+ this.id = builder.id;
+ this.creationTimestamp = builder.creationTimestamp;
+ this.subnetworkId = checkNotNull(builder.subnetworkId);
+ this.description = builder.description;
+ this.gatewayAddress = builder.gatewayAddress;
+ this.network = builder.network;
+ this.ipRange = builder.ipRange;
+ }
+
+ /**
+ * Returns the unique identifier for the subnetwork; defined by the service.
+ */
+ public String id() {
+ return id;
+ }
+
+ /**
+ * Returns the creation timestamp in milliseconds since epoch.
+ */
+ public Long creationTimestamp() {
+ return creationTimestamp;
+ }
+
+ /**
+ * Returns the subnetwork identity.
+ */
+ public SubnetworkId subnetworkId() {
+ return subnetworkId;
+ }
+
+ /**
+ * Returns a textual description of the subnetwork.
+ */
+ public String description() {
+ return description;
+ }
+
+ /**
+ * Returns the gateway IPv4 address for this subnetwork, selected by the service.
+ */
+ public String gatewayAddress() {
+ return gatewayAddress;
+ }
+
+ /**
+ * Returns the identity of the network to which this subnetwork belongs. Only networks that are in
+ * subnet mode can have subnetworks.
+ */
+ public NetworkId network() {
+ return network;
+ }
+
+ /**
+ * Returns the range of internal IPv4 addresses that are owned by this subnetwork. This range is a
+ * CIDR specification, for example: {@code 192.168.0.0/16}. Ranges must be unique and
+ * non-overlapping within a network.
+ *
+ * @see CIDR
+ */
+ public String ipRange() {
+ return ipRange;
+ }
+
+ /**
+ * Returns a builder for the current subnetwork.
+ */
+ public Builder toBuilder() {
+ return new BuilderImpl(this);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("id", id)
+ .add("creationTimestamp", creationTimestamp)
+ .add("subnetworkId", subnetworkId)
+ .add("description", description)
+ .add("gatewayAddress", gatewayAddress)
+ .add("network", network)
+ .add("ipRange", ipRange)
+ .toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, creationTimestamp, subnetworkId, description, gatewayAddress, network,
+ ipRange);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null
+ && obj.getClass().equals(SubnetworkInfo.class)
+ && Objects.equals(toPb(), ((SubnetworkInfo) obj).toPb());
+ }
+
+ SubnetworkInfo setProjectId(String projectId) {
+ return toBuilder()
+ .subnetworkId(subnetworkId.setProjectId(projectId))
+ .network(network.setProjectId(projectId))
+ .build();
+ }
+
+ Subnetwork toPb() {
+ Subnetwork subnetworkPb = new Subnetwork();
+ if (id != null) {
+ subnetworkPb.setId(new BigInteger(id));
+ }
+ if (creationTimestamp != null) {
+ subnetworkPb.setCreationTimestamp(TIMESTAMP_FORMATTER.print(creationTimestamp));
+ }
+ subnetworkPb.setName(subnetworkId.subnetwork());
+ subnetworkPb.setDescription(description);
+ subnetworkPb.setSelfLink(subnetworkId.selfLink());
+ subnetworkPb.setGatewayAddress(gatewayAddress);
+ subnetworkPb.setNetwork(network.selfLink());
+ subnetworkPb.setIpCidrRange(ipRange);
+ return subnetworkPb;
+ }
+
+ /**
+ * Returns a builder for a {@code SubnetworkInfo} object given the identity of the subnetwork, the
+ * identity of the network this subnetwork belongs to and the range of IPv4 addresses owned by
+ * this subnetwork. {@code ipRange} must be a CIDR specification, for example:
+ * {@code 192.168.0.0/16}.
+ *
+ * @see CIDR
+ */
+ public static Builder builder(SubnetworkId subnetworkId, NetworkId network, String ipRange) {
+ return new BuilderImpl(subnetworkId, network, ipRange);
+ }
+
+ /**
+ * Returns a {@code SubnetworkInfo} object given the identity of the subnetwork, the identity of
+ * the network this subnetwork belongs to and the range of IPv4 addresses owned by this
+ * subnetwork. {@code ipRange} must be a CIDR specification, for example: {@code 192.168.0.0/16}.
+ *
+ * @see CIDR
+ */
+ public static SubnetworkInfo of(SubnetworkId subnetworkId, NetworkId network, String ipRange) {
+ return builder(subnetworkId, network, ipRange).build();
+ }
+
+ static SubnetworkInfo fromPb(Subnetwork subnetworkPb) {
+ return new BuilderImpl(subnetworkPb).build();
+ }
+}
diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/NetworkIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/NetworkIdTest.java
new file mode 100644
index 000000000000..08b012d25d62
--- /dev/null
+++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/NetworkIdTest.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 NetworkIdTest {
+
+ private static final String PROJECT = "project";
+ private static final String NETWORK = "network";
+ private static final String URL =
+ "https://www.googleapis.com/compute/v1/projects/project/global/networks/network";
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testOf() {
+ NetworkId networkId = NetworkId.of(PROJECT, NETWORK);
+ assertEquals(PROJECT, networkId.project());
+ assertEquals(NETWORK, networkId.network());
+ assertEquals(URL, networkId.selfLink());
+ networkId = NetworkId.of(NETWORK);
+ assertNull(networkId.project());
+ assertEquals(NETWORK, networkId.network());
+ }
+
+ @Test
+ public void testToAndFromUrl() {
+ NetworkId networkId = NetworkId.of(PROJECT, NETWORK);
+ compareNetworkId(networkId, NetworkId.fromUrl(networkId.selfLink()));
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("notMatchingUrl is not a valid network URL");
+ NetworkId.fromUrl("notMatchingUrl");
+ }
+
+ @Test
+ public void testSetProjectId() {
+ NetworkId networkId = NetworkId.of(PROJECT, NETWORK);
+ assertSame(networkId, networkId.setProjectId(PROJECT));
+ compareNetworkId(networkId, NetworkId.of(NETWORK).setProjectId(PROJECT));
+ }
+
+ @Test
+ public void testMatchesUrl() {
+ assertTrue(NetworkId.matchesUrl(NetworkId.of(PROJECT, NETWORK).selfLink()));
+ assertFalse(NetworkId.matchesUrl("notMatchingUrl"));
+ }
+
+ private void compareNetworkId(NetworkId expected, NetworkId value) {
+ assertEquals(expected, value);
+ assertEquals(expected.project(), expected.project());
+ assertEquals(expected.network(), expected.network());
+ assertEquals(expected.selfLink(), expected.selfLink());
+ assertEquals(expected.hashCode(), expected.hashCode());
+ }
+}
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 bec8844ae111..5f06d252af34 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
@@ -156,6 +156,11 @@ public class SerializationTest {
private static final DiskInfo DISK_INFO = DiskInfo.of(DISK_ID, STANDARD_DISK_CONFIGURATION);
private static final Disk DISK =
new Disk.Builder(COMPUTE, DISK_ID, STANDARD_DISK_CONFIGURATION).build();
+ private static final SubnetworkId SUBNETWORK_ID =
+ SubnetworkId.of("project", "region", "subnetwork");
+ private static final NetworkId NETWORK_ID = NetworkId.of("project", "network");
+ private static final SubnetworkInfo SUBNETWORK_INFO =
+ SubnetworkInfo.of(SUBNETWORK_ID, NETWORK_ID, "192.168.0.0/16");
private static final Compute.DiskTypeOption DISK_TYPE_OPTION =
Compute.DiskTypeOption.fields();
private static final Compute.DiskTypeFilter DISK_TYPE_FILTER =
@@ -241,11 +246,12 @@ public void testModelAndRequests() throws Exception {
ADDRESS_INFO, ADDRESS, DISK_ID, SNAPSHOT_ID, SNAPSHOT_INFO, SNAPSHOT, IMAGE_ID,
DISK_IMAGE_CONFIGURATION, STORAGE_IMAGE_CONFIGURATION, IMAGE_INFO, IMAGE,
STANDARD_DISK_CONFIGURATION, IMAGE_DISK_CONFIGURATION, SNAPSHOT_DISK_CONFIGURATION,
- DISK_INFO, DISK, 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,
+ DISK_INFO, DISK, SUBNETWORK_ID, NETWORK_ID, SUBNETWORK_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, SNAPSHOT_OPTION, SNAPSHOT_FILTER,
SNAPSHOT_LIST_OPTION, IMAGE_OPTION, IMAGE_FILTER, IMAGE_LIST_OPTION, DISK_OPTION,
DISK_FILTER, DISK_LIST_OPTION, DISK_AGGREGATED_LIST_OPTION};
diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkIdTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkIdTest.java
new file mode 100644
index 000000000000..25e428c9009b
--- /dev/null
+++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkIdTest.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 SubnetworkIdTest {
+
+ private static final String PROJECT = "project";
+ private static final String REGION = "region";
+ private static final String NAME = "subnet";
+ private static final String URL =
+ "https://www.googleapis.com/compute/v1/projects/project/regions/region/subnetworks/subnet";
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testOf() {
+ SubnetworkId subnetworkId = SubnetworkId.of(PROJECT, REGION, NAME);
+ assertEquals(PROJECT, subnetworkId.project());
+ assertEquals(REGION, subnetworkId.region());
+ assertEquals(NAME, subnetworkId.subnetwork());
+ assertEquals(URL, subnetworkId.selfLink());
+ subnetworkId = SubnetworkId.of(REGION, NAME);
+ assertNull(subnetworkId.project());
+ assertEquals(REGION, subnetworkId.region());
+ assertEquals(NAME, subnetworkId.subnetwork());
+ subnetworkId = SubnetworkId.of(RegionId.of(PROJECT, REGION), NAME);
+ assertEquals(PROJECT, subnetworkId.project());
+ assertEquals(REGION, subnetworkId.region());
+ assertEquals(NAME, subnetworkId.subnetwork());
+ }
+
+ @Test
+ public void testToAndFromUrl() {
+ SubnetworkId subnetworkId = SubnetworkId.of(PROJECT, REGION, NAME);
+ compareSubnetworkId(subnetworkId, SubnetworkId.fromUrl(subnetworkId.selfLink()));
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("notMatchingUrl is not a valid subnetwork URL");
+ SubnetworkId.fromUrl("notMatchingUrl");
+ }
+
+ @Test
+ public void testSetProjectId() {
+ SubnetworkId subnetworkId = SubnetworkId.of(PROJECT, REGION, NAME);
+ assertSame(subnetworkId, subnetworkId.setProjectId(PROJECT));
+ compareSubnetworkId(subnetworkId, SubnetworkId.of(REGION, NAME).setProjectId(PROJECT));
+ }
+
+ @Test
+ public void testMatchesUrl() {
+ assertTrue(SubnetworkId.matchesUrl(SubnetworkId.of(PROJECT, REGION, NAME).selfLink()));
+ assertFalse(SubnetworkId.matchesUrl("notMatchingUrl"));
+ }
+
+ private void compareSubnetworkId(SubnetworkId expected, SubnetworkId value) {
+ assertEquals(expected, value);
+ assertEquals(expected.project(), expected.project());
+ assertEquals(expected.region(), expected.region());
+ assertEquals(expected.subnetwork(), expected.subnetwork());
+ assertEquals(expected.selfLink(), expected.selfLink());
+ assertEquals(expected.hashCode(), expected.hashCode());
+ }
+}
diff --git a/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkInfoTest.java b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkInfoTest.java
new file mode 100644
index 000000000000..64d2e92852c9
--- /dev/null
+++ b/gcloud-java-compute/src/test/java/com/google/gcloud/compute/SubnetworkInfoTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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 org.junit.Test;
+
+public class SubnetworkInfoTest {
+
+ private static final String ID = "42";
+ private static final Long CREATION_TIMESTAMP = 1453293540000L;
+ private static final String DESCRIPTION = "description";
+ private static final SubnetworkId SUBNETWORK_ID =
+ SubnetworkId.of("project", "region", "subnetwork");
+ private static final String GATEWAY_ADDRESS = "192.168.1.1";
+ private static final NetworkId NETWORK_ID = NetworkId.of("project", "network");
+ private static final String IP_CIDR_RANGE = "192.168.0.0/16";
+ private static final SubnetworkInfo SUBNETWORK_INFO =
+ SubnetworkInfo.builder(SUBNETWORK_ID, NETWORK_ID, IP_CIDR_RANGE)
+ .id(ID)
+ .creationTimestamp(CREATION_TIMESTAMP)
+ .description(DESCRIPTION)
+ .gatewayAddress(GATEWAY_ADDRESS)
+ .build();
+
+ @Test
+ public void testToBuilder() {
+ compareSubnetworkInfo(SUBNETWORK_INFO, SUBNETWORK_INFO.toBuilder().build());
+ SubnetworkInfo subnetworkInfo =
+ SUBNETWORK_INFO.toBuilder().description("newDescription").build();
+ assertEquals("newDescription", subnetworkInfo.description());
+ subnetworkInfo = subnetworkInfo.toBuilder().description("description").build();
+ compareSubnetworkInfo(SUBNETWORK_INFO, subnetworkInfo);
+ }
+
+ @Test
+ public void testToBuilderIncomplete() {
+ SubnetworkInfo subnetworkInfo = SubnetworkInfo.of(SUBNETWORK_ID, NETWORK_ID, IP_CIDR_RANGE);
+ assertEquals(subnetworkInfo, subnetworkInfo.toBuilder().build());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertEquals(ID, SUBNETWORK_INFO.id());
+ assertEquals(SUBNETWORK_ID, SUBNETWORK_INFO.subnetworkId());
+ assertEquals(CREATION_TIMESTAMP, SUBNETWORK_INFO.creationTimestamp());
+ assertEquals(DESCRIPTION, SUBNETWORK_INFO.description());
+ assertEquals(GATEWAY_ADDRESS, SUBNETWORK_INFO.gatewayAddress());
+ assertEquals(NETWORK_ID, SUBNETWORK_INFO.network());
+ assertEquals(IP_CIDR_RANGE, SUBNETWORK_INFO.ipRange());
+ }
+
+ @Test
+ public void testOf() {
+ SubnetworkInfo subnetworkInfo = SubnetworkInfo.of(SUBNETWORK_ID, NETWORK_ID, IP_CIDR_RANGE);
+ assertNull(subnetworkInfo.id());
+ assertEquals(SUBNETWORK_ID, subnetworkInfo.subnetworkId());
+ assertNull(subnetworkInfo.creationTimestamp());
+ assertNull(subnetworkInfo.description());
+ assertNull(subnetworkInfo.gatewayAddress());
+ assertEquals(NETWORK_ID, subnetworkInfo.network());
+ assertEquals(IP_CIDR_RANGE, subnetworkInfo.ipRange());
+ }
+
+ @Test
+ public void testToAndFromPb() {
+ compareSubnetworkInfo(SUBNETWORK_INFO, SubnetworkInfo.fromPb(SUBNETWORK_INFO.toPb()));
+ SubnetworkInfo subnetworkInfo = SubnetworkInfo.of(SUBNETWORK_ID, NETWORK_ID, IP_CIDR_RANGE);
+ compareSubnetworkInfo(subnetworkInfo, SubnetworkInfo.fromPb(subnetworkInfo.toPb()));
+ }
+
+ @Test
+ public void testSetProjectId() {
+ SubnetworkInfo subnetworkInfo = SUBNETWORK_INFO.toBuilder()
+ .subnetworkId(SubnetworkId.of("region", "subnetwork"))
+ .network(NetworkId.of("network"))
+ .build();
+ compareSubnetworkInfo(SUBNETWORK_INFO, subnetworkInfo.setProjectId("project"));
+ }
+
+ public void compareSubnetworkInfo(SubnetworkInfo expected, SubnetworkInfo value) {
+ assertEquals(expected, value);
+ assertEquals(expected.id(), value.id());
+ assertEquals(expected.subnetworkId(), value.subnetworkId());
+ assertEquals(expected.creationTimestamp(), value.creationTimestamp());
+ assertEquals(expected.description(), value.description());
+ assertEquals(expected.gatewayAddress(), value.gatewayAddress());
+ assertEquals(expected.network(), value.network());
+ assertEquals(expected.ipRange(), value.ipRange());
+ assertEquals(expected.hashCode(), value.hashCode());
+ }
+}