You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2014/11/07 17:08:01 UTC

[1/5] jclouds-labs-google git commit: Use InstanceTemplate.name as opposed to ignoring it.

Repository: jclouds-labs-google
Updated Branches:
  refs/heads/master 867c785be -> 04c02a993


Use InstanceTemplate.name as opposed to ignoring it.


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/commit/04c02a99
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/tree/04c02a99
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/diff/04c02a99

Branch: refs/heads/master
Commit: 04c02a993209a6a100104e747837ed2ef63506dc
Parents: 8895953
Author: Adrian Cole <ac...@twitter.com>
Authored: Thu Nov 6 21:00:36 2014 -0800
Committer: Adrian Cole <ac...@twitter.com>
Committed: Fri Nov 7 07:57:33 2014 -0800

----------------------------------------------------------------------
 .../binders/InstanceBinder.java                 | 57 --------------------
 .../GoogleComputeEngineServiceAdapter.java      |  6 ++-
 .../GoogleComputeEngineHttpApiModule.java       | 30 -----------
 .../domain/templates/InstanceTemplate.java      | 17 ++----
 .../features/InstanceApi.java                   |  5 +-
 .../features/InstanceApiExpectTest.java         | 12 +++--
 .../features/InstanceApiLiveTest.java           |  3 +-
 .../features/TargetPoolApiLiveTest.java         |  7 +--
 8 files changed, 22 insertions(+), 115 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/binders/InstanceBinder.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/binders/InstanceBinder.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/binders/InstanceBinder.java
deleted file mode 100644
index aae9d38..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/binders/InstanceBinder.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.binders;
-
-import java.net.URI;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.jclouds.googlecomputeengine.domain.templates.InstanceTemplate;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.rest.MapBinder;
-import org.jclouds.rest.binders.BindToJsonPayload;
-
-import com.google.common.base.Function;
-
-public final class InstanceBinder implements MapBinder {
-
-   private final BindToJsonPayload jsonBinder;
-   private final Function<String, URI> machineTypesToURI;
-
-   @Inject InstanceBinder(BindToJsonPayload jsonBinder,
-         @Named("machineTypeToURI") Function<String, URI> machineTypesToURI) {
-      this.jsonBinder = jsonBinder;
-      this.machineTypesToURI = machineTypesToURI;
-   }
-
-   @Override public <R extends HttpRequest> R bindToRequest(R request, Map<String, Object> postParams) {
-      InstanceTemplate template = (InstanceTemplate) postParams.get("template");
-      template.name(postParams.get("name").toString());
-
-      if (template.machineTypeName() != null) {
-         template.machineType(machineTypesToURI.apply(template.machineTypeName()));
-         template.machineTypeName(null);
-      }
-      return bindToRequest(request, template);
-   }
-
-   @Override public <R extends HttpRequest> R bindToRequest(R request, Object input) {
-      return jsonBinder.bindToRequest(request, input);
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
index 586f137..9a9187e 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
@@ -142,7 +142,9 @@ public final class GoogleComputeEngineServiceAdapter
 
       disks.addAll(options.getDisks());
 
-      InstanceTemplate instanceTemplate = new InstanceTemplate().machineType(hardware.getUri());
+      InstanceTemplate instanceTemplate = new InstanceTemplate()
+            .name(name)
+            .machineType(hardware.getUri());
 
       if (options.isEnableNat()) {
          instanceTemplate.addNetworkInterface(options.getNetwork().get(), Type.ONE_TO_ONE_NAT);
@@ -167,7 +169,7 @@ public final class GoogleComputeEngineServiceAdapter
 
       String zone = template.getLocation().getId();
       InstanceApi instanceApi = api.getInstanceApi(userProject.get(), zone);
-      Operation operation = instanceApi.create(name, instanceTemplate);
+      Operation operation = instanceApi.create(instanceTemplate);
 
       if (options.shouldBlockUntilRunning()) {
          waitOperationDone(operation);

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
index 23fed76..20e26d7 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
@@ -20,7 +20,6 @@ import static com.google.common.base.Suppliers.compose;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
 
-import java.net.URI;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.inject.Named;
@@ -28,10 +27,8 @@ import javax.inject.Singleton;
 
 import org.jclouds.domain.Credentials;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
-import org.jclouds.googlecomputeengine.compute.domain.SlashEncodedIds;
 import org.jclouds.googlecomputeengine.handlers.GoogleComputeEngineErrorHandler;
 import org.jclouds.http.HttpErrorHandler;
-import org.jclouds.http.Uris;
 import org.jclouds.http.annotation.ClientError;
 import org.jclouds.http.annotation.Redirection;
 import org.jclouds.http.annotation.ServerError;
@@ -94,31 +91,4 @@ public final class GoogleComputeEngineHttpApiModule extends HttpApiModule<Google
                  }
               }, creds), seconds, SECONDS);
    }
-
-   @Provides
-   @Singleton
-   @Named("machineTypeToURI") Function<String, URI> machineTypeNameToURI(
-         @Provider final Supplier<URI> endpoint, @UserProject final Supplier<String> userProject) {
-      return new Function<String, URI>() {
-         @Override
-         public URI apply(String input) {
-            SlashEncodedIds zoneAndMachineType = SlashEncodedIds.fromSlashEncoded(input);
-            return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get())
-                    .appendPath("/zones/").appendPath(zoneAndMachineType.left())
-                    .appendPath("/machineTypes/").appendPath(zoneAndMachineType.right()).build();
-         }
-      };
-   }
-
-   @Provides
-   @Singleton
-   @Named("networkToURI") Function<String, URI> networkNameToURI(@Provider final Supplier<URI> endpoint,
-                                                                 @UserProject final Supplier<String> userProject) {
-      return new Function<String, URI>() {
-         @Override public URI apply(String input) {
-            return Uris.uriBuilder(endpoint.get()).appendPath("/projects/").appendPath(userProject.get())
-                    .appendPath("/global/networks/").appendPath(input).build();
-         }
-      };
-   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/templates/InstanceTemplate.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/templates/InstanceTemplate.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/templates/InstanceTemplate.java
index f726234..c544453 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/templates/InstanceTemplate.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/templates/InstanceTemplate.java
@@ -24,6 +24,7 @@ import java.net.URI;
 import java.util.List;
 import java.util.Map;
 
+import org.jclouds.googlecomputeengine.domain.Image;
 import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig;
 import org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type;
 import org.jclouds.googlecomputeengine.domain.Instance.ServiceAccount;
@@ -34,6 +35,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 /** Optional information for creating an instance. */
+// TODO! this is dangerously similarly named to the InstanceTemplate resource!
 public class InstanceTemplate {
 
    public static final class PersistentDisk {
@@ -107,7 +109,6 @@ public class InstanceTemplate {
    private List<PersistentDisk> disks = Lists.newArrayList();
    private List<NetworkInterface> networkInterfaces = Lists.newArrayList();
    private Map<String, String> metadata = Maps.newLinkedHashMap();
-   private String machineTypeName;
 
    /**
     * @see org.jclouds.googlecomputeengine.domain.Instance#name()
@@ -134,7 +135,7 @@ public class InstanceTemplate {
    }
 
    /**
-    * @see org.jclouds.googlecomputeengine.domain.Instance#image()
+    * @see Image#selfLink()
     */
    public URI image() {
       return image;
@@ -158,18 +159,6 @@ public class InstanceTemplate {
    }
 
    /**
-    * @see org.jclouds.googlecomputeengine.domain.Instance#machineTypeName()
-    */
-   public String machineTypeName() {
-      return machineTypeName;
-   }
-
-   public InstanceTemplate machineTypeName(String machineTypeName) {
-      this.machineTypeName = machineTypeName;
-      return this;
-   }
-
-   /**
     * @see org.jclouds.googlecomputeengine.domain.Instance#disks()
     */
    public List<PersistentDisk> disks() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
index 41524ec..17ec3e8 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
@@ -38,7 +38,6 @@ import javax.ws.rs.QueryParam;
 import org.jclouds.Fallbacks.NullOnNotFoundOr404;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyIteratorOnNotFoundOr404;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyListPageOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.binders.InstanceBinder;
 import org.jclouds.googlecomputeengine.binders.MetadataBinder;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.ListPage;
@@ -78,7 +77,6 @@ public interface InstanceApi {
    /**
     * Creates a instance resource in the specified project using the data included in the request.
     *
-    * @param instance this name of the instance to be created
     * @param template the instance template
     * @return an Operation resource. To check on the status of an operation, poll the Operations resource returned to
     *         you, and look for the status field.
@@ -87,8 +85,7 @@ public interface InstanceApi {
    @POST
    @Produces(APPLICATION_JSON)
    @OAuthScopes(COMPUTE_SCOPE)
-   @MapBinder(InstanceBinder.class)
-   Operation create(@PayloadParam("name") String instance, @PayloadParam("template") InstanceTemplate template);
+   Operation create(@BinderParam(BindToJsonPayload.class) InstanceTemplate template);
 
    /** Deletes an instance by name and returns the operation in progress, or null if not found. */
    @Named("Instances:delete")

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java
index 03c6876..351cabe 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiExpectTest.java
@@ -137,10 +137,12 @@ public class InstanceApiExpectTest extends BaseGoogleComputeEngineApiExpectTest
               TOKEN_RESPONSE, insert,
               CREATE_INSTANCE_RESPONSE)).getInstanceApi("myproject", "us-central1-a");
 
-      InstanceTemplate options = new InstanceTemplate().machineTypeName("us-central1-a/n1-standard-1")
+      InstanceTemplate options = new InstanceTemplate()
+              .name("test-1")
+              .machineType(URI.create(BASE_URL + "/myproject/zones/us-central1-a/machineTypes/n1-standard-1"))
               .addNetworkInterface(URI.create(BASE_URL + "/myproject/global/networks/default"));
 
-      assertEquals(api.create("test-1", options), new ParseZoneOperationTest().expected());
+      assertEquals(api.create(options), new ParseZoneOperationTest().expected());
    }
 
    public void testInsertInstanceResponseIs2xxAllOptions() {
@@ -161,7 +163,9 @@ public class InstanceApiExpectTest extends BaseGoogleComputeEngineApiExpectTest
               requestForScopes(COMPUTE_SCOPE),
               TOKEN_RESPONSE, insert, insertInstanceResponse)).getInstanceApi("myproject", "us-central1-a");
 
-      InstanceTemplate options = new InstanceTemplate().machineTypeName("us-central1-a/n1-standard-1")
+      InstanceTemplate options = new InstanceTemplate()
+              .name("test-0")
+              .machineType(URI.create(BASE_URL + "/myproject/zones/us-central1-a/machineTypes/n1-standard-1"))
               .addNetworkInterface(
                     URI.create(BASE_URL + "/myproject/global/networks/default"),
                     Instance.NetworkInterface.AccessConfig.Type.ONE_TO_ONE_NAT)
@@ -172,7 +176,7 @@ public class InstanceApiExpectTest extends BaseGoogleComputeEngineApiExpectTest
               .addServiceAccount(Instance.ServiceAccount.create("default", ImmutableList.of("myscope")))
               .addMetadata("aKey", "aValue");
 
-      assertEquals(api.create("test-0", options), new ParseZoneOperationTest().expected());
+      assertEquals(api.create(options), new ParseZoneOperationTest().expected());
    }
 
    public void testDeleteInstanceResponseIs2xx() {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
index a7ec619..161844b 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
@@ -82,6 +82,7 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
                         .get()
                         .selfLink();
       instance = new InstanceTemplate()
+              .name(INSTANCE_NAME)
               .machineType(getDefaultMachineTypeUrl(userProject.get()))
               .addNetworkInterface(getNetworkUrl(userProject.get(), INSTANCE_NETWORK_NAME),
                                    Instance.NetworkInterface.AccessConfig.Type.ONE_TO_ONE_NAT)
@@ -113,7 +114,7 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
       DiskCreationOptions diskCreationOptions = new DiskCreationOptions().sourceImage(instance.image());
       assertOperationDoneSuccessfully(diskApi().create(BOOT_DISK_NAME, DEFAULT_DISK_SIZE_GB, diskCreationOptions));
       assertOperationDoneSuccessfully(diskApi().create("instance-live-test-disk", DEFAULT_DISK_SIZE_GB));
-      assertOperationDoneSuccessfully(api().create(INSTANCE_NAME, instance));
+      assertOperationDoneSuccessfully(api().create(instance));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertInstance")

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/04c02a99/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
index 37fcacf..038f04f 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
@@ -16,6 +16,7 @@
  */
 package org.jclouds.googlecomputeengine.features;
 
+import static org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type.ONE_TO_ONE_NAT;
 import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotEquals;
@@ -85,9 +86,9 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
       // Make and instanceTemplate
       InstanceTemplate instanceTemplate = new InstanceTemplate()
+            .name(INSTANCE_NAME)
             .machineType(getDefaultMachineTypeUrl(userProject.get()))
-            .addNetworkInterface(getNetworkUrl(userProject.get(), INSTANCE_NETWORK_NAME),
-                                 Instance.NetworkInterface.AccessConfig.Type.ONE_TO_ONE_NAT)
+            .addNetworkInterface(getNetworkUrl(userProject.get(), INSTANCE_NETWORK_NAME), ONE_TO_ONE_NAT)
             .addMetadata("mykey", "myvalue")
             .description("a description")
             .addDisk(Instance.AttachedDisk.Mode.READ_WRITE, getDiskUrl(userProject.get(), BOOT_DISK_NAME),
@@ -105,7 +106,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
                   .create(BOOT_DISK_NAME, DEFAULT_DISK_SIZE_GB, diskCreationOptions));
 
       // Create an instance.
-      assertOperationDoneSuccessfully(instanceApi.create(INSTANCE_NAME, instanceTemplate));
+      assertOperationDoneSuccessfully(instanceApi.create(instanceTemplate));
       Instance instance = instanceApi.get(INSTANCE_NAME);
       instances = new ArrayList<URI>();
       instances.add(instance.selfLink());


[3/5] jclouds-labs-google git commit: Consolidate operation state management.

Posted by ad...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java
deleted file mode 100644
index 5205589..0000000
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiLiveTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.maxResults;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-
-import java.util.Iterator;
-
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
-import org.testng.SkipException;
-import org.testng.annotations.Test;
-
-@Test(groups = "live", testName = "GlobalOperationApiLiveTest")
-public class GlobalOperationApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
-
-   private Operation operation;
-
-   private GlobalOperationApi api() {
-      return api.getGlobalOperationApi(userProject.get());
-   }
-
-   public void testListOperationsWithFiltersAndPagination() {
-      Iterator<ListPage<Operation>> operations = api().list(maxResults(1));
-
-      // make sure that in spite of having only one result per page we get at least two results
-      int count = 0;
-      for (; count < 2 && operations.hasNext(); ) {
-         ListPage<Operation> result = operations.next();
-         if (result.isEmpty()) {
-            operation = result.get(0);
-            count++;
-         }
-      }
-      if (count < 2) {
-         throw new SkipException("Not enough global operations");
-      }
-      assertEquals(count, 2);
-   }
-
-   @Test(groups = "live", dependsOnMethods = "testListOperationsWithFiltersAndPagination")
-   public void testGetOperation() {
-      Operation result = api().get(operation.name());
-      assertNotNull(result);
-      assertEquals(result.name(), operation.name()); // Checking state besides name can lead to flaky test.
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/HttpHealthCheckApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/HttpHealthCheckApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/HttpHealthCheckApiLiveTest.java
index 9b70697..4123ad1 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/HttpHealthCheckApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/HttpHealthCheckApiLiveTest.java
@@ -32,8 +32,6 @@ import com.google.common.collect.Iterables;
 public class HttpHealthCheckApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    private static final String HTTP_HEALTH_CHECK_NAME = "http-health-check-api-live-test";
-   private static final int TIME_WAIT = 60;
-
    private static final int OFFSET = 2;
 
    private HttpHealthCheckCreationOptions options;
@@ -51,7 +49,7 @@ public class HttpHealthCheckApiLiveTest extends BaseGoogleComputeEngineApiLiveTe
                      .healthyThreshold(30)
                      .unhealthyThreshold(15)
                      .description("A First Health Check!");
-      assertGlobalOperationDoneSucessfully(api().insert(HTTP_HEALTH_CHECK_NAME, options), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().insert(HTTP_HEALTH_CHECK_NAME, options));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertHttpHealthCheck")
@@ -79,7 +77,7 @@ public class HttpHealthCheckApiLiveTest extends BaseGoogleComputeEngineApiLiveTe
          .port(options.port() + OFFSET)
          .checkIntervalSec(options.checkIntervalSec() + OFFSET)
          .timeoutSec(options.timeoutSec() + OFFSET);
-      assertGlobalOperationDoneSucessfully(api().patch(HTTP_HEALTH_CHECK_NAME, newOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().patch(HTTP_HEALTH_CHECK_NAME, newOptions));
 
       // Check changes happened and others unchanged.
       HttpHealthCheck httpHealthCheck = api().get(HTTP_HEALTH_CHECK_NAME);
@@ -98,7 +96,7 @@ public class HttpHealthCheckApiLiveTest extends BaseGoogleComputeEngineApiLiveTe
       HttpHealthCheckCreationOptions newOptions = new HttpHealthCheckCreationOptions()
          .checkIntervalSec(options.checkIntervalSec() - OFFSET)
          .timeoutSec(options.timeoutSec() - OFFSET);
-      assertGlobalOperationDoneSucessfully(api().update(HTTP_HEALTH_CHECK_NAME, newOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().update(HTTP_HEALTH_CHECK_NAME, newOptions));
 
       // Check changes happened.
       HttpHealthCheck httpHealthCheck = api().get(HTTP_HEALTH_CHECK_NAME);
@@ -114,6 +112,6 @@ public class HttpHealthCheckApiLiveTest extends BaseGoogleComputeEngineApiLiveTe
 
    @Test(groups = "live", dependsOnMethods = {"testListHttpHealthCheck", "testUpdateHttpHealthCheck"})
    public void testDeleteHttpHealthCheck() {
-      assertGlobalOperationDoneSucessfully(api().delete(HTTP_HEALTH_CHECK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(HTTP_HEALTH_CHECK_NAME));
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java
index 2fc56a1..17bc13f 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ImageApiLiveTest.java
@@ -33,7 +33,6 @@ import org.testng.annotations.Test;
 public class ImageApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    public static final String DISK_NAME = "image-api-live-test-disk";
-   public static final int TIME_WAIT = 300;
    public static final int sizeGb = 10;
    public static final String IMAGE_NAME = "image-api-live-test-image";
 
@@ -77,14 +76,14 @@ public class ImageApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertDisk() {
-      assertZoneOperationDoneSuccessfully(diskApi().create(DISK_NAME, sizeGb), TIME_WAIT);
+      assertOperationDoneSuccessfully(diskApi().create(DISK_NAME, sizeGb));
       Disk disk = diskApi().get(DISK_NAME);
       diskURI = disk.selfLink();
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertDisk")
    public void testCreateImageFromPD(){
-      assertGlobalOperationDoneSucessfully(imageApi().createFromDisk(IMAGE_NAME, diskURI.toString()), TIME_WAIT);
+      assertOperationDoneSuccessfully(imageApi().createFromDisk(IMAGE_NAME, diskURI.toString()));
    }
 
    @Test(groups = "live", dependsOnMethods = "testCreateImageFromPD")
@@ -95,8 +94,8 @@ public class ImageApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testGetCreatedImage")
    public void testCleanup(){
-      assertGlobalOperationDoneSucessfully(imageApi().delete(IMAGE_NAME), TIME_WAIT);
-      assertZoneOperationDoneSuccessfully(diskApi().delete(DISK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(imageApi().delete(IMAGE_NAME));
+      assertOperationDoneSuccessfully(diskApi().delete(DISK_NAME));
    }
 
    private void assertImageEquals(Image result) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
index 84a8a2d..a7ec619 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/InstanceApiLiveTest.java
@@ -19,6 +19,7 @@ package org.jclouds.googlecomputeengine.features;
 import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 import java.net.URI;
@@ -52,7 +53,7 @@ import com.google.inject.Module;
 public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    private static final String INSTANCE_NETWORK_NAME = "instance-api-live-test-network";
-   private static final String INSTANCE_NAME = "instance-api-live-test-instance";
+   private static final String INSTANCE_NAME = "test-1";
    private static final String BOOT_DISK_NAME = INSTANCE_NAME + "-boot-disk";
    private static final String DISK_NAME = "instance-live-test-disk";
    private static final String IPV4_RANGE = "10.0.0.0/8";
@@ -61,9 +62,7 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    private static final List<String> TAGS = ImmutableList.of("instance-live-test-tag1", "instance-live-test-tag2");
    private static final String ATTACH_DISK_NAME = "instance-api-live-test-attach-disk";
    private static final String ATTACH_DISK_DEVICE_NAME = "attach-disk-1";
-
    private static final int DEFAULT_DISK_SIZE_GB = 10;
-   private static final int TIME_WAIT = 600;
 
    private InstanceTemplate instance;
 
@@ -108,20 +107,17 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    public void testInsertInstance() {
 
       // need to insert the network first
-      assertGlobalOperationDoneSucessfully(api.getNetworkApi(userProject.get()).createInIPv4Range
-              (INSTANCE_NETWORK_NAME, IPV4_RANGE), TIME_WAIT);
+      assertOperationDoneSuccessfully(api.getNetworkApi(userProject.get()).createInIPv4Range
+              (INSTANCE_NETWORK_NAME, IPV4_RANGE));
 
       DiskCreationOptions diskCreationOptions = new DiskCreationOptions().sourceImage(instance.image());
-      assertZoneOperationDoneSuccessfully(diskApi().create(BOOT_DISK_NAME, DEFAULT_DISK_SIZE_GB, diskCreationOptions),
-            TIME_WAIT);
-
-      assertZoneOperationDoneSuccessfully(diskApi().create("instance-live-test-disk", DEFAULT_DISK_SIZE_GB), TIME_WAIT);
-      assertZoneOperationDoneSuccessfully(api().create(INSTANCE_NAME, instance), TIME_WAIT);
+      assertOperationDoneSuccessfully(diskApi().create(BOOT_DISK_NAME, DEFAULT_DISK_SIZE_GB, diskCreationOptions));
+      assertOperationDoneSuccessfully(diskApi().create("instance-live-test-disk", DEFAULT_DISK_SIZE_GB));
+      assertOperationDoneSuccessfully(api().create(INSTANCE_NAME, instance));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertInstance")
    public void testGetInstance() {
-
       Instance instance = api().get(INSTANCE_NAME);
       assertNotNull(instance);
       assertInstanceEquals(instance, this.instance);
@@ -130,9 +126,8 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    @Test(groups = "live", dependsOnMethods = "testListInstance")
    public void testSetMetadataForInstance() {
       Instance originalInstance = api().get(INSTANCE_NAME);
-      assertZoneOperationDoneSuccessfully(api().setMetadata(INSTANCE_NAME,
-                  ImmutableMap.of(METADATA_ITEM_KEY, METADATA_ITEM_VALUE), originalInstance.metadata().fingerprint()),
-            TIME_WAIT);
+      assertOperationDoneSuccessfully(api().setMetadata(INSTANCE_NAME,
+                  ImmutableMap.of(METADATA_ITEM_KEY, METADATA_ITEM_VALUE), originalInstance.metadata().fingerprint()));
 
       Instance modifiedInstance = api().get(INSTANCE_NAME);
 
@@ -145,8 +140,8 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    @Test(groups = "live", dependsOnMethods = "testListInstance")
    public void testSetTagsForInstance() {
       Instance originalInstance = api().get(INSTANCE_NAME);
-      assertZoneOperationDoneSuccessfully(
-            api().setTags(INSTANCE_NAME, TAGS, originalInstance.tags().fingerprint()), TIME_WAIT);
+      assertOperationDoneSuccessfully(
+            api().setTags(INSTANCE_NAME, TAGS, originalInstance.tags().fingerprint()));
 
       Instance modifiedInstance = api().get(INSTANCE_NAME);
 
@@ -156,13 +151,13 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testSetMetadataForInstance")
    public void testAttachDiskToInstance() {
-      assertZoneOperationDoneSuccessfully(diskApi().create(ATTACH_DISK_NAME, 1), TIME_WAIT);
+      assertOperationDoneSuccessfully(diskApi().create(ATTACH_DISK_NAME, 1));
 
       Instance originalInstance = api().get(INSTANCE_NAME);
-      assertZoneOperationDoneSuccessfully(api().attachDisk(INSTANCE_NAME,
+      assertOperationDoneSuccessfully(api().attachDisk(INSTANCE_NAME,
                   new AttachDiskOptions().type(DiskType.PERSISTENT)
                         .source(getDiskUrl(userProject.get(), ATTACH_DISK_NAME)).mode(DiskMode.READ_ONLY)
-                        .deviceName(ATTACH_DISK_DEVICE_NAME)), TIME_WAIT);
+                        .deviceName(ATTACH_DISK_DEVICE_NAME)));
 
       Instance modifiedInstance = api().get(INSTANCE_NAME);
 
@@ -180,13 +175,13 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    @Test(groups = "live", dependsOnMethods = "testAttachDiskToInstance")
    public void testDetachDiskFromInstance() {
       Instance originalInstance = api().get(INSTANCE_NAME);
-      assertZoneOperationDoneSuccessfully(api().detachDisk(INSTANCE_NAME, ATTACH_DISK_DEVICE_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().detachDisk(INSTANCE_NAME, ATTACH_DISK_DEVICE_NAME));
 
       Instance modifiedInstance = api().get(INSTANCE_NAME);
 
       assertTrue(modifiedInstance.disks().size() < originalInstance.disks().size());
 
-      assertZoneOperationDoneSuccessfully(diskApi().delete(ATTACH_DISK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(diskApi().delete(ATTACH_DISK_NAME));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertInstance")
@@ -204,16 +199,16 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testDetachDiskFromInstance")
    public void testResetInstance() {
-      assertZoneOperationDoneSuccessfully(api().reset(INSTANCE_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().reset(INSTANCE_NAME));
    }
 
    @Test(groups = "live", dependsOnMethods = "testResetInstance")
    public void testDeleteInstance() {
-      assertZoneOperationDoneSuccessfully(api().delete(INSTANCE_NAME), TIME_WAIT);
-      assertZoneOperationDoneSuccessfully(diskApi().delete(DISK_NAME), TIME_WAIT);
-      assertZoneOperationDoneSuccessfully(diskApi().delete(BOOT_DISK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(INSTANCE_NAME));
+      assertOperationDoneSuccessfully(diskApi().delete(DISK_NAME));
+      assertNull(diskApi().get(BOOT_DISK_NAME)); // auto-delete!
       Operation deleteNetwork = api.getNetworkApi(userProject.get()).delete(INSTANCE_NETWORK_NAME);
-      assertGlobalOperationDoneSucessfully(deleteNetwork, TIME_WAIT);
+      assertOperationDoneSuccessfully(deleteNetwork);
    }
 
    private void assertInstanceEquals(Instance result, InstanceTemplate expected) {
@@ -224,10 +219,9 @@ public class InstanceApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    @AfterClass(groups = { "integration", "live" })
    protected void tearDownContext() {
       try {
-         waitZoneOperationDone(api().delete(INSTANCE_NAME), TIME_WAIT);
-         waitZoneOperationDone(diskApi().delete(DISK_NAME), TIME_WAIT);
-         waitZoneOperationDone(diskApi().delete(BOOT_DISK_NAME), TIME_WAIT);
-         waitGlobalOperationDone(api.getNetworkApi(userProject.get()).delete(INSTANCE_NETWORK_NAME), TIME_WAIT);
+         waitOperationDone(api().delete(INSTANCE_NAME));
+         waitOperationDone(diskApi().delete(DISK_NAME));
+         waitOperationDone(api.getNetworkApi(userProject.get()).delete(INSTANCE_NETWORK_NAME));
       } catch (Exception e) {
          // we don't really care about any exception here, so just delete away.
        }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
index 080b63c..e814462 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/NetworkApiLiveTest.java
@@ -33,7 +33,6 @@ public class NetworkApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    private static final String NETWORK_NAME = "network-api-live-test-network";
    private static final String IPV4_RANGE = "10.0.0.0/8";
-   private static final int TIME_WAIT = 10;
 
    private NetworkApi api() {
       return api.getNetworkApi(userProject.get());
@@ -41,7 +40,7 @@ public class NetworkApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertNetwork() {
-      assertGlobalOperationDoneSucessfully(api().createInIPv4Range(NETWORK_NAME, IPV4_RANGE), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().createInIPv4Range(NETWORK_NAME, IPV4_RANGE));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertNetwork")
@@ -64,7 +63,7 @@ public class NetworkApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testListNetwork")
    public void testDeleteNetwork() {
-      assertGlobalOperationDoneSucessfully(api().delete(NETWORK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(NETWORK_NAME));
    }
 
    private void assertNetworkEquals(Network result) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiExpectTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiExpectTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiExpectTest.java
new file mode 100644
index 0000000..36edf75
--- /dev/null
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiExpectTest.java
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.googlecomputeengine.features;
+
+import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
+import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
+import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNull;
+
+import org.jclouds.googlecomputeengine.domain.ListPage;
+import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest;
+import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationListTest;
+import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationTest;
+import org.jclouds.googlecomputeengine.parse.ParseRegionOperationTest;
+import org.jclouds.googlecomputeengine.parse.ParseZoneOperationTest;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.http.HttpResponse;
+import org.testng.annotations.Test;
+
+import com.google.common.collect.ImmutableList;
+
+@Test(groups = "unit", testName = "OperationApiExpectTest")
+public class OperationApiExpectTest extends BaseGoogleComputeEngineApiExpectTest {
+
+   private static final String OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/global/operations";
+   private static final String REGION_OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/regions/us-central1/operations";
+   private static final String ZONE_OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/zones/us-central1-a/operations";
+
+   public static final HttpRequest GET_GLOBAL_OPERATION_REQUEST = HttpRequest
+           .builder()
+           .method("GET")
+           .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb")
+           .addHeader("Accept", "application/json")
+           .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+   public static final HttpResponse GET_GLOBAL_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200)
+           .payload(staticPayloadFromResource("/global_operation.json")).build();
+
+   public void get() throws Exception {
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+              TOKEN_RESPONSE, GET_GLOBAL_OPERATION_REQUEST, GET_GLOBAL_OPERATION_RESPONSE).getOperationApi("myproject");
+
+      assertEquals(api.get(GET_GLOBAL_OPERATION_REQUEST.getEndpoint()),
+              new ParseGlobalOperationTest().expected());
+   }
+
+   public void getResponseIs4xx() throws Exception {
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+              TOKEN_RESPONSE, GET_GLOBAL_OPERATION_REQUEST, operationResponse).getOperationApi("myproject");
+
+      assertNull(api.get(GET_GLOBAL_OPERATION_REQUEST.getEndpoint()));
+   }
+
+   public void delete() throws Exception {
+      HttpRequest delete = HttpRequest
+              .builder()
+              .method("DELETE")
+              .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
+              .addHeader("Accept", "application/json")
+              .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
+              TOKEN_RESPONSE, delete, operationResponse).getOperationApi("myproject");
+
+      api.delete(delete.getEndpoint());
+   }
+
+   public void deleteResponseIs4xx() throws Exception {
+      HttpRequest delete = HttpRequest
+              .builder()
+              .method("DELETE")
+              .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
+              .addHeader("Accept", "application/json")
+              .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
+              TOKEN_RESPONSE, delete, operationResponse).getOperationApi("myproject");
+
+      api.delete(delete.getEndpoint());
+   }
+
+   public void list() {
+      HttpRequest get = HttpRequest
+              .builder()
+              .method("GET")
+              .endpoint(OPERATIONS_URL_PREFIX)
+              .addHeader("Accept", "application/json")
+              .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/global_operation_list.json")).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+              TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertEquals(api.list().next().toString(),
+              new ParseGlobalOperationListTest().expected().toString());
+   }
+
+   public void listResponseIs4xx() {
+      HttpRequest get = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(OPERATIONS_URL_PREFIX)
+            .addHeader("Accept", "application/json")
+            .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+            TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertFalse(api.list().hasNext());
+   }
+
+   public void listWithOptions() {
+      HttpRequest get = HttpRequest
+              .builder()
+              .method("GET")
+              .endpoint(OPERATIONS_URL_PREFIX +
+                      "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" +
+                      "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" +
+                      "filter=" +
+                      "status%20eq%20done&" +
+                      "maxResults=3")
+              .addHeader("Accept", "application/json")
+              .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
+              .payload(payloadFromResource("/global_operation_list.json")).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+              TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertEquals(api.listPage("CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" +
+              "I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz",
+              filter("status eq done").maxResults(3)).toString(),
+              new ParseGlobalOperationListTest().expected().toString());
+   }
+
+   private ListPage<Operation> regionList() {
+      return ListPage.create( //
+            ImmutableList.of(new ParseRegionOperationTest().expected()), // items
+            null // nextPageToken
+      );
+   }
+
+   public void listInRegion() {
+      HttpRequest get = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(REGION_OPERATIONS_URL_PREFIX)
+            .addHeader("Accept", "application/json")
+            .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/region_operation_list.json")).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+            TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertEquals(api.listInRegion("us-central1").next().toString(), regionList().toString());
+   }
+
+   public void listInRegionResponseIs4xx() {
+      HttpRequest get = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(REGION_OPERATIONS_URL_PREFIX)
+            .addHeader("Accept", "application/json")
+            .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+            TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertFalse(api.listInRegion("us-central1").hasNext());
+   }
+
+   public void listPageInRegion() {
+      HttpRequest get = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(REGION_OPERATIONS_URL_PREFIX +
+                  "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" +
+                  "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" +
+                  "filter=" +
+                  "status%20eq%20done&" +
+                  "maxResults=3")
+            .addHeader("Accept", "application/json")
+            .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/region_operation_list.json")).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+            TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertEquals(api.listPageInRegion("us-central1",
+                  "CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz",
+                  filter("status eq done").maxResults(3)).toString(), regionList().toString());
+   }
+
+
+   private ListPage<Operation> zoneList() {
+      return ListPage.create( //
+            ImmutableList.of(new ParseZoneOperationTest().expected()), // items
+            null // nextPageToken
+      );
+   }
+
+   public void listInZone() {
+      HttpRequest get = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(ZONE_OPERATIONS_URL_PREFIX)
+            .addHeader("Accept", "application/json")
+            .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/zone_operation_list.json")).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+            TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertEquals(api.listInZone("us-central1-a").next().toString(), zoneList().toString());
+   }
+
+   public void listInZoneResponseIs4xx() {
+      HttpRequest get = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(ZONE_OPERATIONS_URL_PREFIX)
+            .addHeader("Accept", "application/json")
+            .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+            TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertFalse(api.listInZone("us-central1-a").hasNext());
+   }
+
+   public void listPageInZone() {
+      HttpRequest get = HttpRequest
+            .builder()
+            .method("GET")
+            .endpoint(ZONE_OPERATIONS_URL_PREFIX +
+                  "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" +
+                  "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" +
+                  "filter=" +
+                  "status%20eq%20done&" +
+                  "maxResults=3")
+            .addHeader("Accept", "application/json")
+            .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
+            .payload(payloadFromResource("/zone_operation_list.json")).build();
+
+      OperationApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
+            TOKEN_RESPONSE, get, operationResponse).getOperationApi("myproject");
+
+      assertEquals(api.listPageInZone("us-central1-a",
+            "CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz",
+            filter("status eq done").maxResults(3)).toString(), zoneList().toString());
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiLiveTest.java
new file mode 100644
index 0000000..9b8e6da
--- /dev/null
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/OperationApiLiveTest.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.googlecomputeengine.features;
+
+import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.maxResults;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.util.Iterator;
+
+import org.jclouds.googlecomputeengine.domain.ListPage;
+import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
+import org.testng.SkipException;
+import org.testng.annotations.Test;
+
+@Test(groups = "live", testName = "GlobalOperationApiLiveTest")
+public class OperationApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
+
+   private Operation operation;
+
+   private OperationApi api() {
+      return api.getOperationApi(userProject.get());
+   }
+
+   public void listWithOptions() {
+      Iterator<ListPage<Operation>> operations = api().list(maxResults(1));
+
+      // make sure that in spite of having only one result per page we get at least two results
+      int count = 0;
+      for (; count < 2 && operations.hasNext(); ) {
+         ListPage<Operation> result = operations.next();
+         if (result.isEmpty()) {
+            operation = result.get(0);
+            count++;
+         }
+      }
+      if (count < 2) {
+         throw new SkipException("Not enough global operations");
+      }
+      assertEquals(count, 2);
+   }
+
+   @Test(groups = "live", dependsOnMethods = "listWithOptions")
+   public void testGetOperation() {
+      Operation result = api().get(operation.selfLink());
+      assertNotNull(result);
+      assertEquals(result.name(), operation.name()); // Checking state besides name can lead to flaky test.
+   }
+
+   public void listInRegionWithOptions() {
+      Iterator<ListPage<Operation>> operations = api().listInRegion(DEFAULT_REGION_NAME, maxResults(1));
+
+      // make sure that in spite of having only one result per page we get at least two results
+      int count = 0;
+      for (; count < 2 && operations.hasNext(); ) {
+         ListPage<Operation> result = operations.next();
+         if (result.isEmpty()) {
+            count++;
+         }
+      }
+      if (count < 2) {
+         throw new SkipException("Not enough region operations");
+      }
+      assertEquals(count, 2);
+   }
+
+   public void listInZoneWithOptions() {
+      Iterator<ListPage<Operation>> operations = api().listInZone(DEFAULT_ZONE_NAME, maxResults(1));
+
+      // make sure that in spite of having only one result per page we get at least two results
+      int count = 0;
+      for (; count < 2 && operations.hasNext(); ) {
+         ListPage<Operation> result = operations.next();
+         if (result.isEmpty()) {
+            count++;
+         }
+      }
+      if (count < 2) {
+         throw new SkipException("Not enough zone operations");
+      }
+      assertEquals(count, 2);
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java
index 45c180d..984d185 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ProjectApiLiveTest.java
@@ -33,8 +33,6 @@ import org.testng.annotations.Test;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 
-/**
- */
 public class ProjectApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    private static final String METADATA_ITEM_KEY = "projectLiveTestTestProp";
@@ -66,8 +64,8 @@ public class ProjectApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    public void addItemToMetadata() {
       this.initialMetadataSize = project.commonInstanceMetadata().items().size();
       this.initialFingerprint = this.project.commonInstanceMetadata().fingerprint();
-      assertGlobalOperationDoneSucessfully(addItemToMetadata(projectApi(), userProject.get(), METADATA_ITEM_KEY,
-              METADATA_ITEM_VALUE), 20);
+      assertOperationDoneSuccessfully(addItemToMetadata(projectApi(), userProject.get(), METADATA_ITEM_KEY,
+              METADATA_ITEM_VALUE));
       this.project = projectApi().get(userProject.get());
       assertNotNull(project);
       assertTrue(this.project.commonInstanceMetadata().items().containsKey(METADATA_ITEM_KEY),
@@ -79,7 +77,7 @@ public class ProjectApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "addItemToMetadata")
    public void testDeleteItemFromMetadata() {
-      assertGlobalOperationDoneSucessfully(deleteItemFromMetadata(projectApi(), userProject.get(), METADATA_ITEM_KEY), 20);
+      assertOperationDoneSuccessfully(deleteItemFromMetadata(projectApi(), userProject.get(), METADATA_ITEM_KEY));
       this.project = projectApi().get(userProject.get());
       assertNotNull(project);
       assertFalse(project.commonInstanceMetadata().items().containsKey(METADATA_ITEM_KEY));
@@ -115,8 +113,6 @@ public class ProjectApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
       ImmutableMap.Builder<String, String> metadataBuilder = ImmutableMap.builder();
       metadataBuilder.putAll(Maps.filterKeys(project.commonInstanceMetadata().items(), not(equalTo(key))));
       return projectApi.setCommonInstanceMetadata(projectName, metadataBuilder.build(),
-              project.commonInstanceMetadata().fingerprint());
+            project.commonInstanceMetadata().fingerprint());
    }
-
-
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java
deleted file mode 100644
index ce7fdc8..0000000
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiExpectTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
-import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNull;
-
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest;
-import org.jclouds.googlecomputeengine.parse.ParseRegionOperationTest;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-@Test(groups = "unit", testName = "RegionOperationApiExpectTest")
-public class RegionOperationApiExpectTest extends BaseGoogleComputeEngineApiExpectTest {
-
-   private static final String OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/regions/us-central1/operations";
-
-   private static final String DELETE_OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/regions/us-central1/operations";
-
-   public static final HttpRequest GET_OPERATION_REQUEST = HttpRequest
-           .builder()
-           .method("GET")
-           .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb")
-           .addHeader("Accept", "application/json")
-           .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-   public static final HttpResponse GET_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200)
-           .payload(staticPayloadFromResource("/region_operation.json")).build();
-
-   private ListPage<Operation> expectedList() {
-      return ListPage.create( //
-            ImmutableList.of(new ParseRegionOperationTest().expected()), // items
-            null // nextPageToken
-      );
-   }
-
-   public void testGetOperationResponseIs2xx() throws Exception {
-
-      RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-            TOKEN_RESPONSE, GET_OPERATION_REQUEST, GET_OPERATION_RESPONSE)
-            .getRegionOperationApi("myproject", "us-central1");
-
-      assertEquals(regionOperationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb"),
-            new ParseRegionOperationTest().expected());
-   }
-
-   public void testGetOperationResponseIs4xx() throws Exception {
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-            TOKEN_RESPONSE, GET_OPERATION_REQUEST, operationResponse).getRegionOperationApi("myproject", "us-central1");
-
-      assertNull(regionOperationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb"));
-   }
-
-   public void testDeleteOperationResponseIs2xx() throws Exception {
-      HttpRequest delete = HttpRequest
-              .builder()
-              .method("DELETE")
-              .endpoint(DELETE_OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build();
-
-      RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
-              TOKEN_RESPONSE, delete, operationResponse).getRegionOperationApi("myproject", "us-central1");
-
-      regionOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
-   }
-
-   public void testDeleteOperationResponseIs4xx() throws Exception {
-      HttpRequest delete = HttpRequest
-              .builder()
-              .method("DELETE")
-              .endpoint(DELETE_OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
-              TOKEN_RESPONSE, delete, operationResponse).getRegionOperationApi("myproject", "us-central1");
-
-      regionOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
-   }
-
-   public void testLisOperationWithNoOptionsResponseIs2xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX)
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
-              .payload(payloadFromResource("/region_operation_list.json")).build();
-
-      RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getRegionOperationApi("myproject", "us-central1");
-
-      assertEquals(regionOperationApi.list().next().toString(), expectedList().toString());
-   }
-
-   public void testListOperationWithPaginationOptionsResponseIs2xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX +
-                      "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" +
-                      "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" +
-                      "filter=" +
-                      "status%20eq%20done&" +
-                      "maxResults=3")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
-              .payload(payloadFromResource("/region_operation_list.json")).build();
-
-      RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getRegionOperationApi("myproject", "us-central1");
-
-      assertEquals(regionOperationApi.listPage("CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" +
-              "I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz", filter("status eq done").maxResults(3)).toString(),
-              expectedList().toString());
-   }
-
-   public void testListOperationWithPaginationOptionsResponseIs4xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX)
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      RegionOperationApi regionOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getRegionOperationApi("myproject", "us-central1");
-
-      assertFalse(regionOperationApi.list().hasNext());
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java
deleted file mode 100644
index f15fbf5..0000000
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RegionOperationApiLiveTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.maxResults;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-
-import java.util.Iterator;
-
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
-import org.testng.SkipException;
-import org.testng.annotations.Test;
-
-@Test(groups = "live", testName = "RegionOperationApiLiveTest")
-public class RegionOperationApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
-
-   private Operation operation;
-
-   private RegionOperationApi api() {
-      return api.getRegionOperationApi(userProject.get(), DEFAULT_REGION_NAME);
-   }
-
-   public void testListOperationsWithFiltersAndPagination() {
-      Iterator<ListPage<Operation>> operations = api().list(maxResults(1));
-
-      // make sure that in spite of having only one result per page we get at least two results
-      int count = 0;
-      for (; count < 2 && operations.hasNext(); ) {
-         ListPage<Operation> result = operations.next();
-         if (result.isEmpty()) {
-            operation = result.get(0);
-            count++;
-         }
-      }
-      if (count < 2) {
-         throw new SkipException("Not enough operations in " + DEFAULT_REGION_NAME);
-      }
-      assertEquals(count, 2);
-   }
-
-   @Test(groups = "live", dependsOnMethods = "testListOperationsWithFiltersAndPagination")
-   public void testGetOperation() {
-      Operation result = api().get(operation.name());
-      assertNotNull(result);
-      assertEquals(result.name(), operation.name()); // Checking state besides name can lead to flaky test.
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
index 2cbaf64..c2631f2 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/RouteApiLiveTest.java
@@ -36,7 +36,6 @@ public class RouteApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    private static final String IPV4_RANGE = "10.0.0.0/8";
    private static final String ROUTE_NAME = "route-api-live-test-route";
    private static final String ROUTE_NETWORK_NAME = "route-api-live-test-network";
-   public static final int TIME_WAIT = 30;
 
    private RouteApi api() {
       return api.getRouteApi(userProject.get());
@@ -44,17 +43,16 @@ public class RouteApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertRoute() {
-      assertGlobalOperationDoneSucessfully(api.getNetworkApi(userProject.get()).createInIPv4Range
-              (ROUTE_NETWORK_NAME, IPV4_RANGE), TIME_WAIT);
-      assertGlobalOperationDoneSucessfully(api().createInNetwork(ROUTE_NAME,
+      assertOperationDoneSuccessfully(api.getNetworkApi(userProject.get()).createInIPv4Range
+              (ROUTE_NETWORK_NAME, IPV4_RANGE));
+      assertOperationDoneSuccessfully(api().createInNetwork(ROUTE_NAME,
               getNetworkUrl(userProject.get(), ROUTE_NETWORK_NAME),
               new RouteOptions().addTag("footag")
                       .addTag("bartag")
                       .description("RouteApi Live Test")
                       .destRange(DEST_RANGE)
                       .priority(1000)
-                      .nextHopGateway(getGatewayUrl(userProject.get(), DEFAULT_GATEWAY_NAME))),
-              TIME_WAIT);
+                      .nextHopGateway(getGatewayUrl(userProject.get(), DEFAULT_GATEWAY_NAME))));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertRoute")
@@ -80,9 +78,8 @@ public class RouteApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testListRoute")
    public void testDeleteRoute() {
-      assertGlobalOperationDoneSucessfully(api().delete(ROUTE_NAME), TIME_WAIT);
-      assertGlobalOperationDoneSucessfully(api.getNetworkApi(userProject.get())
-              .delete(ROUTE_NETWORK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(ROUTE_NAME));
+      assertOperationDoneSuccessfully(api.getNetworkApi(userProject.get()).delete(ROUTE_NETWORK_NAME));
    }
 
    private void assertRouteEquals(Route result) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java
index 8d478b6..61a2191 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/SnapshotApiLiveTest.java
@@ -16,7 +16,6 @@
  */
 package org.jclouds.googlecomputeengine.features;
 
-import static org.jclouds.googlecomputeengine.features.DiskApiLiveTest.TIME_WAIT;
 import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
 import static org.testng.Assert.assertEquals;
 
@@ -45,10 +44,10 @@ public class SnapshotApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testCreateSnapshot() {
-      assertZoneOperationDoneSuccessfully(diskApi().create(DISK_NAME, 1), TIME_WAIT);
+      assertOperationDoneSuccessfully(diskApi().create(DISK_NAME, 1));
       disk = diskApi().get(DISK_NAME);
 
-      assertZoneOperationDoneSuccessfully(diskApi().createSnapshot(DISK_NAME, SNAPSHOT_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(diskApi().createSnapshot(DISK_NAME, SNAPSHOT_NAME));
    }
 
    @Test(groups = "live", dependsOnMethods = "testCreateSnapshot")
@@ -72,8 +71,8 @@ public class SnapshotApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testListSnapshot")
    public void testDeleteDisk() {
-      assertZoneOperationDoneSuccessfully(diskApi().delete(DISK_NAME), TIME_WAIT);
-      assertGlobalOperationDoneSucessfully(api().delete(SNAPSHOT_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(diskApi().delete(DISK_NAME));
+      assertOperationDoneSuccessfully(api().delete(SNAPSHOT_NAME));
    }
 
    private void assertSnapshotEquals(Snapshot result) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiExpectTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiExpectTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiExpectTest.java
index 26c016a..147e114 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiExpectTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiExpectTest.java
@@ -65,8 +65,7 @@ public class TargetPoolApiExpectTest extends BaseGoogleComputeEngineApiExpectTes
       TargetPoolApi api = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
               TOKEN_RESPONSE, get, operationResponse).getTargetPoolApi("myproject", "us-central1");
 
-      assertEquals(api.get("test"),
-              new ParseTargetPoolTest().expected());
+      assertEquals(api.get("test"), new ParseTargetPoolTest().expected());
    }
 
    public void testGetTargetPoolResponseIs4xx() throws Exception {
@@ -229,8 +228,7 @@ public class TargetPoolApiExpectTest extends BaseGoogleComputeEngineApiExpectTes
       TargetPoolApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
             TOKEN_RESPONSE, addHealthCheck, operationResponse).getTargetPoolApi("myproject", "us-central1");
 
-      assertEquals(api.addHealthCheck("test", HEALTH_CHECKS),
-            new ParseRegionOperationTest().expected());
+      assertEquals(api.addHealthCheck("test", HEALTH_CHECKS), new ParseRegionOperationTest().expected());
    }
    
    @Test(expectedExceptions = ResourceNotFoundException.class)
@@ -253,8 +251,7 @@ public class TargetPoolApiExpectTest extends BaseGoogleComputeEngineApiExpectTes
       TargetPoolApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
             TOKEN_RESPONSE, removeHealthCheck, operationResponse).getTargetPoolApi("myproject", "us-central1");
 
-      assertEquals(api.removeHealthCheck("test", HEALTH_CHECKS),
-            new ParseRegionOperationTest().expected());
+      assertEquals(api.removeHealthCheck("test", HEALTH_CHECKS), new ParseRegionOperationTest().expected());
    }
    
    @Test(expectedExceptions = ResourceNotFoundException.class)
@@ -283,8 +280,7 @@ public class TargetPoolApiExpectTest extends BaseGoogleComputeEngineApiExpectTes
       TargetPoolApi api = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
             TOKEN_RESPONSE, SetBackup, operationResponse).getTargetPoolApi("myproject", "us-central1");
 
-      assertEquals(api.setBackup("testpool", TARGET_POOL),
-            new ParseRegionOperationTest().expected());
+      assertEquals(api.setBackup("testpool", TARGET_POOL), new ParseRegionOperationTest().expected());
    }
    
    public void testSetBackupWithFailoverRatioResponseIs2xx(){
@@ -304,8 +300,7 @@ public class TargetPoolApiExpectTest extends BaseGoogleComputeEngineApiExpectTes
             TOKEN_RESPONSE, SetBackup, operationResponse).getTargetPoolApi("myproject", "us-central1");
 
       Float failoverRatio = Float.valueOf("0.5");
-      assertEquals(api.setBackup("testpool", failoverRatio, TARGET_POOL),
-            new ParseRegionOperationTest().expected());
+      assertEquals(api.setBackup("testpool", failoverRatio, TARGET_POOL), new ParseRegionOperationTest().expected());
    }
    
    @Test(expectedExceptions = ResourceNotFoundException.class)

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
index 753b81a..37fcacf 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/TargetPoolApiLiveTest.java
@@ -48,7 +48,6 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    private static final String BACKUP_TARGETPOOL_NAME = "targetpool-api-live-test-backup";
    private static final String TARGETPOOL_NAME = "targetpool-api-live-test-primary";
    private static final String THIRD_TARGETPOOL_NAME = "targetpool-apo-live-test-third";
-   private static final int TIME_WAIT = 30;
    private static final String DESCRIPTION = "A New TargetPool!";
    private static final String DESCRIPTION_BACKUP = "A backup target pool!";
 
@@ -59,7 +58,6 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    private static final String HEALTHCHECK_NAME = "target-pool-test-health-check";
 
    private static final int DEFAULT_DISK_SIZE_GB = 10;
-   private static final int TIME_WAIT_LONG = 600;
 
    private List<URI> instances;
    private List<URI> httpHealthChecks;
@@ -98,17 +96,16 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
 
       // Insert a network.
-      assertGlobalOperationDoneSucessfully(api.getNetworkApi(userProject.get()).createInIPv4Range
-              (INSTANCE_NETWORK_NAME, IPV4_RANGE), TIME_WAIT_LONG);
+      assertOperationDoneSuccessfully(api.getNetworkApi(userProject.get()).createInIPv4Range
+              (INSTANCE_NETWORK_NAME, IPV4_RANGE));
 
       // Create a disk.
       DiskCreationOptions diskCreationOptions = new DiskCreationOptions().sourceImage(instanceTemplate.image());
-      assertZoneOperationDoneSuccessfully(api.getDiskApi(userProject.get(), DEFAULT_ZONE_NAME)
-                  .create(BOOT_DISK_NAME, DEFAULT_DISK_SIZE_GB, diskCreationOptions), TIME_WAIT_LONG);
+      assertOperationDoneSuccessfully(api.getDiskApi(userProject.get(), DEFAULT_ZONE_NAME)
+                  .create(BOOT_DISK_NAME, DEFAULT_DISK_SIZE_GB, diskCreationOptions));
 
       // Create an instance.
-      assertZoneOperationDoneSuccessfully(instanceApi.create(INSTANCE_NAME, instanceTemplate),
-            TIME_WAIT_LONG);
+      assertOperationDoneSuccessfully(instanceApi.create(INSTANCE_NAME, instanceTemplate));
       Instance instance = instanceApi.get(INSTANCE_NAME);
       instances = new ArrayList<URI>();
       instances.add(instance.selfLink());
@@ -118,7 +115,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
          .checkIntervalSec(30)
          .timeoutSec(20)
          .description("A test HealthCheck for adding to targetPools");
-      assertGlobalOperationDoneSucessfully(httpHealthCheckApi.insert(HEALTHCHECK_NAME, options), TIME_WAIT);
+      assertOperationDoneSuccessfully(httpHealthCheckApi.insert(HEALTHCHECK_NAME, options));
       HttpHealthCheck healthCheck = httpHealthCheckApi.get(HEALTHCHECK_NAME);
       httpHealthChecks = new ArrayList<URI>();
       httpHealthChecks.add(healthCheck.selfLink());
@@ -129,7 +126,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
       TargetPoolCreationOptions targetPoolCreationOptions = new TargetPoolCreationOptions()
       .description(DESCRIPTION_BACKUP)
       .sessionAffinity(SessionAffinityValue.CLIENT_IP);
-      assertRegionOperationDoneSucessfully(api().create(BACKUP_TARGETPOOL_NAME, targetPoolCreationOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().create(BACKUP_TARGETPOOL_NAME, targetPoolCreationOptions));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertTargetPool")
@@ -142,7 +139,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
          .sessionAffinity(SessionAffinityValue.CLIENT_IP)
          .backupPool(targetPool.selfLink())
          .failoverRatio((float) 0.5);
-      assertRegionOperationDoneSucessfully(api().create(TARGETPOOL_NAME, targetPoolCreationOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().create(TARGETPOOL_NAME, targetPoolCreationOptions));
       TargetPool targetPool2 = api().get(TARGETPOOL_NAME);
       assertNotNull(targetPool2);
       assertEquals(targetPool2.name(), TARGETPOOL_NAME);
@@ -163,7 +160,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = {"testInsertTargetPool", "testCreateInstanceAndHealthCheck"})
    public void testAddInstanceTargetPool() {
-      assertRegionOperationDoneSucessfully(api().addInstance(BACKUP_TARGETPOOL_NAME, instances), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().addInstance(BACKUP_TARGETPOOL_NAME, instances));
       TargetPool targetPool = api().get(BACKUP_TARGETPOOL_NAME);
       assertNotNull(targetPool);
       assertEquals(targetPool.name(), BACKUP_TARGETPOOL_NAME);
@@ -172,7 +169,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testAddInstanceTargetPool")
    public void testRemoveInstanceTargetPool() {
-      assertRegionOperationDoneSucessfully(api().removeInstance(BACKUP_TARGETPOOL_NAME, instances), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().removeInstance(BACKUP_TARGETPOOL_NAME, instances));
 
       TargetPool targetPool = api().get(BACKUP_TARGETPOOL_NAME);
 
@@ -183,7 +180,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = {"testInsertTargetPool2", "testCreateInstanceAndHealthCheck"})
    public void testAddHealthCheckTargetPool() {
-      assertRegionOperationDoneSucessfully(api().addHealthCheck(TARGETPOOL_NAME, httpHealthChecks), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().addHealthCheck(TARGETPOOL_NAME, httpHealthChecks));
       TargetPool targetPool = api().get(TARGETPOOL_NAME);
       assertNotNull(targetPool);
       assertEquals(targetPool.name(), TARGETPOOL_NAME);
@@ -192,7 +189,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testAddHealthCheckTargetPool")
    public void testRemoveHealthCheckTargetPool() {
-      assertRegionOperationDoneSucessfully(api().removeHealthCheck(TARGETPOOL_NAME, httpHealthChecks), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().removeHealthCheck(TARGETPOOL_NAME, httpHealthChecks));
 
       TargetPool targetPool = api().get(TARGETPOOL_NAME);
 
@@ -210,7 +207,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    @Test(groups = "live", dependsOnMethods = {"testInsertTargetPool2"})
    public void testListBackupTargetPool() {
       TargetPoolCreationOptions options = new TargetPoolCreationOptions().description("A targetPool for testing setBackup.");
-      assertRegionOperationDoneSucessfully(api().create(THIRD_TARGETPOOL_NAME, options), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().create(THIRD_TARGETPOOL_NAME, options));
       TargetPool targetPool = api().get(THIRD_TARGETPOOL_NAME);
       assertNotNull(targetPool);
       assertEquals(targetPool.name(), THIRD_TARGETPOOL_NAME);
@@ -219,7 +216,7 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
       URI selfLink = api().get(TARGETPOOL_NAME).selfLink();
 
       Float failoverRatio = Float.valueOf((float) 0.5);
-      assertRegionOperationDoneSucessfully(api().setBackup(THIRD_TARGETPOOL_NAME, failoverRatio, selfLink), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().setBackup(THIRD_TARGETPOOL_NAME, failoverRatio, selfLink));
 
       TargetPool targetPoolUpdated = api().get(THIRD_TARGETPOOL_NAME);
       assertNotNull(targetPoolUpdated);
@@ -234,9 +231,9 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
                                               "testListBackupTargetPool"}, alwaysRun = true)
    public void testDeleteTargetPool() {
       // Note: This ordering matters due one being the backup of the other ect.
-      assertRegionOperationDoneSucessfully(api().delete(THIRD_TARGETPOOL_NAME), TIME_WAIT);
-      assertRegionOperationDoneSucessfully(api().delete(TARGETPOOL_NAME), TIME_WAIT);
-      assertRegionOperationDoneSucessfully(api().delete(BACKUP_TARGETPOOL_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(THIRD_TARGETPOOL_NAME));
+      assertOperationDoneSuccessfully(api().delete(TARGETPOOL_NAME));
+      assertOperationDoneSuccessfully(api().delete(BACKUP_TARGETPOOL_NAME));
    }
 
    @AfterClass(groups = { "integration", "live" })
@@ -245,10 +242,10 @@ public class TargetPoolApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
       HttpHealthCheckApi httpHealthCheckApi = api.getHttpHealthCheckApi(userProject.get());
 
       try {
-         waitZoneOperationDone(instanceApi.delete(INSTANCE_NAME), TIME_WAIT_LONG);
-         waitZoneOperationDone(api.getDiskApi(userProject.get(), DEFAULT_ZONE_NAME).delete(BOOT_DISK_NAME), TIME_WAIT);
-         waitGlobalOperationDone(api.getNetworkApi(userProject.get()).delete(INSTANCE_NETWORK_NAME), TIME_WAIT_LONG);
-         waitGlobalOperationDone(httpHealthCheckApi.delete(HEALTHCHECK_NAME), TIME_WAIT);
+         waitOperationDone(instanceApi.delete(INSTANCE_NAME));
+         waitOperationDone(api.getDiskApi(userProject.get(), DEFAULT_ZONE_NAME).delete(BOOT_DISK_NAME));
+         waitOperationDone(api.getNetworkApi(userProject.get()).delete(INSTANCE_NETWORK_NAME));
+         waitOperationDone(httpHealthCheckApi.delete(HEALTHCHECK_NAME));
       } catch (Exception e) {
          // we don't really care about any exception here, so just delete away.
        }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java
deleted file mode 100644
index 4a3136a..0000000
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiExpectTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
-import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNull;
-
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest;
-import org.jclouds.googlecomputeengine.parse.ParseZoneOperationTest;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.testng.annotations.Test;
-
-import com.google.common.collect.ImmutableList;
-
-@Test(groups = "unit", testName = "ZoneOperationApiExpectTest")
-public class ZoneOperationApiExpectTest extends BaseGoogleComputeEngineApiExpectTest {
-
-   private static final String OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/zones/us-central1-a/operations";
-
-   public static final HttpRequest GET_ZONE_OPERATION_REQUEST = HttpRequest
-           .builder()
-           .method("GET")
-           .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb")
-           .addHeader("Accept", "application/json")
-           .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-   public static final HttpResponse GET_ZONE_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200)
-           .payload(staticPayloadFromResource("/zone_operation.json")).build();
-
-   public void testGetOperationResponseIs2xx() throws Exception {
-
-      ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-            TOKEN_RESPONSE, GET_ZONE_OPERATION_REQUEST, GET_ZONE_OPERATION_RESPONSE)
-            .getZoneOperationApi("myproject", "us-central1-a");
-
-      assertEquals(zoneOperationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb"),
-            new ParseZoneOperationTest().expected());
-   }
-
-   public void testGetOperationResponseIs4xx() throws Exception {
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-            TOKEN_RESPONSE, GET_ZONE_OPERATION_REQUEST, operationResponse)
-            .getZoneOperationApi("myproject", "us-central1-a");
-
-      assertNull(zoneOperationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb"));
-   }
-
-   public void testDeleteOperationResponseIs2xx() throws Exception {
-      HttpRequest delete = HttpRequest
-              .builder()
-              .method("DELETE")
-              .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build();
-
-      ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE), TOKEN_RESPONSE, delete,
-            operationResponse).getZoneOperationApi("myproject", "us-central1-a");
-
-      zoneOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
-   }
-
-   public void testDeleteOperationResponseIs4xx() throws Exception {
-      HttpRequest delete = HttpRequest
-              .builder()
-              .method("DELETE")
-              .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
-              TOKEN_RESPONSE, delete, operationResponse).getZoneOperationApi("myproject", "us-central1-a");
-
-      zoneOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
-   }
-
-   private static ListPage<Operation> expectedList() {
-      return ListPage.create( //
-            ImmutableList.of(new ParseZoneOperationTest().expected()), // items
-            null // nextPageToken
-      );
-   }
-
-   public void testListOperationWithNoOptionsResponseIs2xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX)
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
-              .payload(payloadFromResource("/zone_operation_list.json")).build();
-
-      ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getZoneOperationApi("myproject", "us-central1-a");
-
-      assertEquals(zoneOperationApi.list().next().toString(),
-              expectedList().toString());
-   }
-
-   public void testListOperationWithPaginationOptionsResponseIs2xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX +
-                      "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" +
-                      "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" +
-                      "filter=" +
-                      "status%20eq%20done&" +
-                      "maxResults=3")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
-              .payload(payloadFromResource("/zone_operation_list.json")).build();
-
-      ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getZoneOperationApi("myproject", "us-central1-a");
-
-      assertEquals(zoneOperationApi.listPage(
-              "CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" +
-                      "I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz",
-              filter("status eq done").maxResults(3)).toString(),
-              expectedList().toString());
-   }
-
-   public void testListOperationWithPaginationOptionsResponseIs4xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX)
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      ZoneOperationApi zoneOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-            TOKEN_RESPONSE, get, operationResponse).getZoneOperationApi("myproject", "us-central1-a");
-
-      assertFalse(zoneOperationApi.list().hasNext());
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java
deleted file mode 100644
index 0d9422f..0000000
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ZoneOperationApiLiveTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.maxResults;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertNotNull;
-
-import java.util.Iterator;
-
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiLiveTest;
-import org.testng.SkipException;
-import org.testng.annotations.Test;
-
-@Test(groups = "live", testName = "ZoneOperationApiLiveTest")
-public class ZoneOperationApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
-
-   private Operation operation;
-
-   private ZoneOperationApi api() {
-      return api.getZoneOperationApi(userProject.get(), DEFAULT_ZONE_NAME);
-   }
-
-   public void testListOperationsWithFiltersAndPagination() {
-      Iterator<ListPage<Operation>> operations = api().list(maxResults(1));
-
-      // make sure that in spite of having only one result per page we get at least two results
-      int count = 0;
-      for (; count < 2 && operations.hasNext(); ) {
-         ListPage<Operation> result = operations.next();
-         if (result.isEmpty()) {
-            operation = result.get(0);
-            count++;
-         }
-      }
-      if (count < 2) {
-         throw new SkipException("Not enough operations in " + DEFAULT_ZONE_NAME);
-      }
-      assertEquals(count, 2);
-   }
-
-   @Test(groups = "live", dependsOnMethods = "testListOperationsWithFiltersAndPagination")
-   public void testGetOperation() {
-      Operation result = api().get(operation.name());
-      assertNotNull(result);
-      assertEquals(result.name(), operation.name()); // Checking state besides name can lead to flaky test.
-   }
-}


[2/5] jclouds-labs-google git commit: Consolidate operation state management.

Posted by ad...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java
index 1a19bcf..07ac7e0 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/internal/BaseGoogleComputeEngineApiLiveTest.java
@@ -16,15 +16,16 @@
  */
 package org.jclouds.googlecomputeengine.internal;
 
-import static java.util.concurrent.TimeUnit.SECONDS;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
 import static org.jclouds.oauth.v2.OAuthTestUtils.setCredential;
-import static org.jclouds.util.Predicates2.retry;
 import static org.testng.Assert.assertEquals;
 import static org.testng.AssertJUnit.assertTrue;
 
 import java.net.URI;
 import java.util.Properties;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.Logger;
 
 import org.jclouds.apis.BaseApiLiveTest;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
@@ -39,7 +40,6 @@ import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.google.inject.Module;
 import com.google.inject.TypeLiteral;
-import com.google.inject.name.Names;
 
 
 public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest<GoogleComputeEngineApi> {
@@ -57,9 +57,7 @@ public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest<GoogleCo
    protected static final String DISK_TYPE_API_URL_SUFFIX = "/diskTypes/";
 
    protected Supplier<String> userProject;
-   protected Predicate<AtomicReference<Operation>> globalOperationDonePredicate;
-   protected Predicate<AtomicReference<Operation>> regionOperationDonePredicate;
-   protected Predicate<AtomicReference<Operation>> zoneOperationDonePredicate;
+   protected Predicate<AtomicReference<Operation>> operationDone;
 
    public BaseGoogleComputeEngineApiLiveTest() {
       provider = "google-compute-engine";
@@ -76,39 +74,25 @@ public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest<GoogleCo
       Injector injector = newBuilder().modules(modules).overrides(props).buildInjector();
       userProject = injector.getInstance(Key.get(new TypeLiteral<Supplier<String>>() {
       }, UserProject.class));
-      globalOperationDonePredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {
-      }, Names.named("global")));
-      regionOperationDonePredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {
-      }, Names.named("region")));
-      zoneOperationDonePredicate = injector.getInstance(Key.get(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {
-      }, Names.named("zone")));
+      operationDone = injector.getInstance(Key.get(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {
+      }));
       return injector.getInstance(GoogleComputeEngineApi.class);
    }
 
-   protected void assertGlobalOperationDoneSucessfully(Operation operation, long maxWaitSeconds) {
-      operation = waitOperationDone(globalOperationDonePredicate, operation, maxWaitSeconds);
-      assertEquals(operation.status(), Operation.Status.DONE);
-      assertTrue(operation.errors().isEmpty());
+   protected void assertOperationDoneSuccessfully(Operation operation) {
+      AtomicReference<Operation> ref = Atomics.newReference(checkNotNull(operation, "operation"));
+      checkState(operationDone.apply(ref), "Timeout waiting for operation: %s", operation);
+      assertEquals(ref.get().status(), Operation.Status.DONE);
+      assertTrue(ref.get().errors().isEmpty());
    }
 
-   protected void waitGlobalOperationDone(Operation operation, long maxWaitSeconds) {
-      waitOperationDone(globalOperationDonePredicate, operation, maxWaitSeconds);
-   }
-
-   protected void assertRegionOperationDoneSucessfully(Operation operation, long maxWaitSeconds) {
-      operation = waitOperationDone(regionOperationDonePredicate, operation, maxWaitSeconds);
-      assertEquals(operation.status(), Operation.Status.DONE);
-      assertTrue(operation.errors().isEmpty());
-   }
-
-   protected void assertZoneOperationDoneSuccessfully(@Nullable Operation operation, long maxWaitSeconds) {
-      operation = waitOperationDone(zoneOperationDonePredicate, operation, maxWaitSeconds);
-      assertEquals(operation.status(), Operation.Status.DONE);
-      assertTrue(operation.errors().isEmpty());
-   }
-
-   protected void waitZoneOperationDone(@Nullable Operation operation, long maxWaitSeconds) {
-      waitOperationDone(zoneOperationDonePredicate, operation, maxWaitSeconds);
+   protected void waitOperationDone(@Nullable Operation operation) {
+      if (operation == null) {
+         return;
+      }
+      if (!operationDone.apply(Atomics.newReference(operation))) {
+         Logger.getAnonymousLogger().warning("Timeout waiting for operation: " + operation);
+      }
    }
 
    protected URI getDiskTypeUrl(String project, String zone, String diskType){
@@ -147,15 +131,5 @@ public class BaseGoogleComputeEngineApiLiveTest extends BaseApiLiveTest<GoogleCo
    protected URI getDiskUrl(String project, String diskName) {
       return URI.create(API_URL_PREFIX + project + ZONE_API_URL_SUFFIX + DEFAULT_ZONE_NAME + "/disks/" + diskName);
    }
-
-   private static Operation waitOperationDone(Predicate<AtomicReference<Operation>> operationDonePredicate,
-                                              @Nullable Operation operation, long maxWaitSeconds) {
-      if (operation == null) { // Null can mean a delete op didn't need to occur.
-         return null;
-      }
-      AtomicReference<Operation> operationReference = Atomics.newReference(operation);
-      retry(operationDonePredicate, maxWaitSeconds, 1, SECONDS).apply(operationReference);
-      return operationReference.get();
-   }
 }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java
index 75a1d92..4b85a01 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseOperationTest.java
@@ -41,7 +41,7 @@ public class ParseOperationTest extends BaseGoogleComputeEngineParseTest<Operati
             URI.create(BASE_URL + "/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb"),
             "operation-1354084865060-4cf88735faeb8-bbbb12cb", // name
             null, // description
-            URI.create(BASE_URL + "/myproject/zones/us-central1-a/instances/instance-api-live-test-instance"), // targetLink
+            URI.create(BASE_URL + "/myproject/zones/us-central1-a/instances/test-1"), // targetLink
             "13053094017547040099", // targetId
             null, // clientOperationId
             Operation.Status.DONE, // status

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneOperationTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneOperationTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneOperationTest.java
index 0e5418d..8c2e006 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneOperationTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/parse/ParseZoneOperationTest.java
@@ -41,7 +41,7 @@ public class ParseZoneOperationTest extends BaseGoogleComputeEngineParseTest<Ope
             URI.create(BASE_URL + "/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb"),
             "operation-1354084865060-4cf88735faeb8-bbbb12cb", // name
             null, // description
-            URI.create(BASE_URL + "/myproject/zones/us-central1-a/instances/instance-api-live-test-instance"),
+            URI.create(BASE_URL + "/myproject/zones/us-central1-a/instances/test-1"),
             "13053094017547040099", // targetId
             null, // clientOperationId
             Operation.Status.DONE, // status

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java
index f01bdab..52e09d1 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicatesTest.java
@@ -17,11 +17,11 @@
 package org.jclouds.googlecomputeengine.predicates;
 
 import static org.jclouds.googlecomputeengine.compute.functions.FirewallToIpPermissionTest.fwForTest;
-import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.equalsIpPermission;
-import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.hasPortRange;
-import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.hasSourceRange;
-import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.hasSourceTag;
-import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.providesIpPermission;
+import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.equalsIpPermission;
+import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.hasPortRange;
+import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.hasSourceRange;
+import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.hasSourceTag;
+import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.providesIpPermission;
 import static org.testng.Assert.assertFalse;
 import static org.testng.Assert.assertTrue;
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/resources/operation.json
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/resources/operation.json b/google-compute-engine/src/test/resources/operation.json
index 7ca83c8..421fb2f 100644
--- a/google-compute-engine/src/test/resources/operation.json
+++ b/google-compute-engine/src/test/resources/operation.json
@@ -3,7 +3,7 @@
    "id": "13053095055850848306",
    "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
    "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
-   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance",
+   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1",
    "targetId": "13053094017547040099",
    "status": "DONE",
    "user": "user@developer.gserviceaccount.com",

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/resources/operation_error.json
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/resources/operation_error.json b/google-compute-engine/src/test/resources/operation_error.json
index 157f786..f72e18c 100644
--- a/google-compute-engine/src/test/resources/operation_error.json
+++ b/google-compute-engine/src/test/resources/operation_error.json
@@ -3,7 +3,7 @@
    "id": "13053095055850848306",
    "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
    "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
-   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance",
+   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1",
    "targetId": "13053094017547040099",
    "status": "DONE",
    "user": "user@developer.gserviceaccount.com",
@@ -16,7 +16,7 @@
       "errors": [
          {
             "code": "RESOURCE_ALREADY_EXISTS",
-            "message": "The resource 'projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance' already exists"
+            "message": "The resource 'projects/myproject/zones/us-central1-a/instances/test-1' already exists"
          }
       ]
    },

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/resources/operation_list.json
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/resources/operation_list.json b/google-compute-engine/src/test/resources/operation_list.json
index c83980d..fd30768 100644
--- a/google-compute-engine/src/test/resources/operation_list.json
+++ b/google-compute-engine/src/test/resources/operation_list.json
@@ -8,7 +8,7 @@
          "id": "13053095055850848306",
          "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
          "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
-         "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance",
+         "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1",
          "targetId": "13053094017547040099",
          "status": "DONE",
          "user": "user@developer.gserviceaccount.com",

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/resources/zone_operation.json
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/resources/zone_operation.json b/google-compute-engine/src/test/resources/zone_operation.json
index c0c5b56..d942086 100644
--- a/google-compute-engine/src/test/resources/zone_operation.json
+++ b/google-compute-engine/src/test/resources/zone_operation.json
@@ -3,7 +3,7 @@
    "id": "13053095055850848306",
    "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
    "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
-   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance",
+   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1",
    "targetId": "13053094017547040099",
    "status": "DONE",
    "user": "user@developer.gserviceaccount.com",

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/resources/zone_operation_error.json
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/resources/zone_operation_error.json b/google-compute-engine/src/test/resources/zone_operation_error.json
index d6d054a..a0e6464 100644
--- a/google-compute-engine/src/test/resources/zone_operation_error.json
+++ b/google-compute-engine/src/test/resources/zone_operation_error.json
@@ -3,7 +3,7 @@
    "id": "13053095055850848306",
    "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
    "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
-   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance",
+   "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1",
    "targetId": "13053094017547040099",
    "status": "DONE",
    "user": "user@developer.gserviceaccount.com",
@@ -16,7 +16,7 @@
       "errors": [
          {
             "code": "RESOURCE_ALREADY_EXISTS",
-            "message": "The resource 'projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance' already exists"
+            "message": "The resource 'projects/myproject/zones/us-central1-a/instances/test-1' already exists"
          }
       ]
    },

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/resources/zone_operation_list.json
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/resources/zone_operation_list.json b/google-compute-engine/src/test/resources/zone_operation_list.json
index 77f1656..212c755 100644
--- a/google-compute-engine/src/test/resources/zone_operation_list.json
+++ b/google-compute-engine/src/test/resources/zone_operation_list.json
@@ -8,7 +8,7 @@
          "id": "13053095055850848306",
          "selfLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/operations/operation-1354084865060-4cf88735faeb8-bbbb12cb",
          "name": "operation-1354084865060-4cf88735faeb8-bbbb12cb",
-         "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/instance-api-live-test-instance",
+         "targetLink": "https://www.googleapis.com/compute/v1/projects/myproject/zones/us-central1-a/instances/test-1",
          "targetId": "13053094017547040099",
          "status": "DONE",
          "user": "user@developer.gserviceaccount.com",


[4/5] jclouds-labs-google git commit: Consolidate operation state management.

Posted by ad...@apache.org.
http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java
deleted file mode 100644
index 4bc0eac..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RegionOperationApi.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static org.jclouds.Fallbacks.VoidOnNotFoundOr404;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
-
-import java.util.Iterator;
-
-import javax.inject.Named;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
-
-import org.jclouds.Fallbacks.NullOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyIteratorOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyListPageOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.functions.internal.ParseRegionOperations;
-import org.jclouds.googlecomputeengine.options.ListOptions;
-import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.oauth.v2.config.OAuthScopes;
-import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
-import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.annotations.Transform;
-
-@SkipEncoding({'/', '='})
-@RequestFilters(OAuthAuthenticationFilter.class)
-@Path("/operations")
-@Consumes(APPLICATION_JSON)
-public interface RegionOperationApi {
-
-   /** Returns an operation by name or null if not found. */
-   @Named("RegionOperations:get")
-   @GET
-   @Path("/{operation}")
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @Fallback(NullOnNotFoundOr404.class)
-   @Nullable
-   Operation get(@PathParam("operation") String operation);
-
-   /** Deletes an operation by name. */
-   @Named("RegionOperations:delete")
-   @DELETE
-   @Path("/{operation}")
-   @OAuthScopes(COMPUTE_SCOPE)
-   @Fallback(VoidOnNotFoundOr404.class)
-   void delete(@PathParam("operation") String operation);
-
-   /**
-    * Retrieves the list of operation resources available to the specified project.
-    * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not
-    * been set.
-    *
-    * @param token       marks the beginning of the next list page
-    * @param listOptions listing options
-    * @return a page of the list
-    */
-   @Named("RegionOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseRegionOperations.class)
-   @Fallback(EmptyListPageOnNotFoundOr404.class)
-   ListPage<Operation> listPage(@Nullable @QueryParam("pageToken") String token, ListOptions listOptions);
-
-   /**
-    * @see #list(org.jclouds.googlecomputeengine.options.ListOptions)
-    */
-   @Named("RegionOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseRegionOperations.class)
-   @Transform(ParseRegionOperations.ToIteratorOfListPage.class)
-   @Fallback(EmptyIteratorOnNotFoundOr404.class)
-   Iterator<ListPage<Operation>> list();
-
-   /**
-    * @see #list(org.jclouds.googlecomputeengine.options.ListOptions)
-    */
-   @Named("RegionOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseRegionOperations.class)
-   @Transform(ParseRegionOperations.ToIteratorOfListPage.class)
-   @Fallback(EmptyIteratorOnNotFoundOr404.class)
-   Iterator<ListPage<Operation>> list(ListOptions options);
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java
index 0919e6d..70594e2 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/RouteApi.java
@@ -91,7 +91,7 @@ public interface RouteApi {
    @POST
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    @MapBinder(RouteBinder.class)
    Operation createInNetwork(@PayloadParam("name") String name,
                              @PayloadParam("network") URI network,

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java
deleted file mode 100644
index e89a10b..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/ZoneOperationApi.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static org.jclouds.Fallbacks.VoidOnNotFoundOr404;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
-
-import java.util.Iterator;
-
-import javax.inject.Named;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
-
-import org.jclouds.Fallbacks.NullOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyIteratorOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyListPageOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.functions.internal.ParseZoneOperations;
-import org.jclouds.googlecomputeengine.options.ListOptions;
-import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.oauth.v2.config.OAuthScopes;
-import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
-import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.annotations.Transform;
-
-@SkipEncoding({'/', '='})
-@RequestFilters(OAuthAuthenticationFilter.class)
-@Path("/operations")
-@Consumes(APPLICATION_JSON)
-public interface ZoneOperationApi {
-
-   /** Returns an operation by name or null if not found. */
-   @Named("ZoneOperations:get")
-   @GET
-   @Path("/{operation}")
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @Fallback(NullOnNotFoundOr404.class)
-   @Nullable
-   Operation get(@PathParam("operation") String operation);
-
-   /** Deletes an operation by name. */
-   @Named("ZoneOperations:delete")
-   @DELETE
-   @Path("/{operation}")
-   @OAuthScopes(COMPUTE_SCOPE)
-   @Fallback(VoidOnNotFoundOr404.class)
-   void delete(@PathParam("operation") String operation);
-
-   /**
-    * Retrieves the list of operation resources available to the specified project.
-    * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not
-    * been set.
-    *
-    * @param token       marks the beginning of the next list page
-    * @param listOptions listing options
-    * @return a page of the list
-    */
-   @Named("ZoneOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseZoneOperations.class)
-   @Fallback(EmptyListPageOnNotFoundOr404.class)
-   ListPage<Operation> listPage(@Nullable @QueryParam("pageToken") String token, ListOptions listOptions);
-
-   /**
-    * @see #list(org.jclouds.googlecomputeengine.options.ListOptions)
-    */
-   @Named("ZoneOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseZoneOperations.class)
-   @Transform(ParseZoneOperations.ToIteratorOfListPage.class)
-   @Fallback(EmptyIteratorOnNotFoundOr404.class)
-   Iterator<ListPage<Operation>> list();
-
-   /**
-    * @see #list(org.jclouds.googlecomputeengine.options.ListOptions)
-    */
-   @Named("ZoneOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseZoneOperations.class)
-   @Transform(ParseZoneOperations.ToIteratorOfListPage.class)
-   @Fallback(EmptyIteratorOnNotFoundOr404.class)
-   Iterator<ListPage<Operation>> list(ListOptions options);
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToIteratorOfListPage.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToIteratorOfListPage.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToIteratorOfListPage.java
index eab19e6..54cbd5b 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToIteratorOfListPage.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithRegionToIteratorOfListPage.java
@@ -37,7 +37,7 @@ import com.google.common.collect.Iterators;
 abstract class BaseWithRegionToIteratorOfListPage<T, I extends BaseWithRegionToIteratorOfListPage<T, I>>
       implements Function<ListPage<T>, Iterator<ListPage<T>>>, InvocationContext<I> {
 
-   private GeneratedHttpRequest request;
+   GeneratedHttpRequest request;
 
    @Override public Iterator<ListPage<T>> apply(ListPage<T> input) {
       if (input.nextPageToken() == null)

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToIteratorOfListPage.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToIteratorOfListPage.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToIteratorOfListPage.java
index 16bc345..5c54f84 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToIteratorOfListPage.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/BaseWithZoneToIteratorOfListPage.java
@@ -37,7 +37,7 @@ import com.google.common.collect.Iterators;
 abstract class BaseWithZoneToIteratorOfListPage<T, I extends BaseWithZoneToIteratorOfListPage<T, I>>
       implements Function<ListPage<T>, Iterator<ListPage<T>>>, InvocationContext<I> {
 
-   private GeneratedHttpRequest request;
+   GeneratedHttpRequest request;
 
    @Override public Iterator<ListPage<T>> apply(ListPage<T> input) {
       if (input.nextPageToken() == null) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java
index f45744f..738dacd 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseGlobalOperations.java
@@ -48,7 +48,7 @@ public final class ParseGlobalOperations extends ParseJson<ListPage<Operation>>
             final ListOptions options) {
          return new Function<String, ListPage<Operation>>() {
             @Override public ListPage<Operation> apply(String input) {
-               return api.getGlobalOperationApi(projectName).listPage(input, options);
+               return api.getOperationApi(projectName).listPage(input, options);
             }
          };
       }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java
index 8b19bd4..506f31d 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseRegionOperations.java
@@ -16,6 +16,11 @@
  */
 package org.jclouds.googlecomputeengine.functions.internal;
 
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.collect.Iterables.tryFind;
+
+import java.util.Iterator;
+
 import javax.inject.Inject;
 
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
@@ -26,6 +31,8 @@ import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterators;
 import com.google.inject.TypeLiteral;
 
 public final class ParseRegionOperations extends ParseJson<ListPage<Operation>> {
@@ -38,6 +45,20 @@ public final class ParseRegionOperations extends ParseJson<ListPage<Operation>>
    public static class ToIteratorOfListPage
          extends BaseWithRegionToIteratorOfListPage<Operation, ToIteratorOfListPage> {
 
+      @Override public Iterator<ListPage<Operation>> apply(ListPage<Operation> input) {
+         if (input.nextPageToken() == null) {
+            return Iterators.singletonIterator(input);
+         }
+
+         String project = (String) request.getCaller().get().getArgs().get(0);
+         String region = (String) request.getInvocation().getArgs().get(0);
+
+         Optional<Object> listOptions = tryFind(request.getInvocation().getArgs(), instanceOf(ListOptions.class));
+
+         return new AdvancingIterator<Operation>(input,
+               fetchNextPage(project, region, (ListOptions) listOptions.orNull()));
+      }
+
       private final GoogleComputeEngineApi api;
 
       @Inject ToIteratorOfListPage(GoogleComputeEngineApi api) {
@@ -48,7 +69,7 @@ public final class ParseRegionOperations extends ParseJson<ListPage<Operation>>
             final String regionName, final ListOptions options) {
          return new Function<String, ListPage<Operation>>() {
             @Override public ListPage<Operation> apply(String input) {
-               return api.getRegionOperationApi(projectName, regionName).listPage(input, options);
+               return api.getOperationApi(projectName).listPageInRegion(regionName, input, options);
             }
          };
       }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java
index de2e6ec..9137642 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/functions/internal/ParseZoneOperations.java
@@ -16,6 +16,11 @@
  */
 package org.jclouds.googlecomputeengine.functions.internal;
 
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.collect.Iterables.tryFind;
+
+import java.util.Iterator;
+
 import javax.inject.Inject;
 
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
@@ -26,6 +31,8 @@ import org.jclouds.http.functions.ParseJson;
 import org.jclouds.json.Json;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.collect.Iterators;
 import com.google.inject.TypeLiteral;
 
 public final class ParseZoneOperations extends ParseJson<ListPage<Operation>> {
@@ -43,12 +50,26 @@ public final class ParseZoneOperations extends ParseJson<ListPage<Operation>> {
          this.api = api;
       }
 
+      @Override public Iterator<ListPage<Operation>> apply(ListPage<Operation> input) {
+         if (input.nextPageToken() == null) {
+            return Iterators.singletonIterator(input);
+         }
+
+         String project = (String) request.getCaller().get().getArgs().get(0);
+         String zone = (String) request.getInvocation().getArgs().get(0);
+
+         Optional<Object> listOptions = tryFind(request.getInvocation().getArgs(), instanceOf(ListOptions.class));
+
+         return new AdvancingIterator<Operation>(input,
+               fetchNextPage(project, zone, (ListOptions) listOptions.orNull()));
+      }
+
       @Override protected Function<String, ListPage<Operation>> fetchNextPage(final String projectName,
             final String zoneName, final ListOptions options) {
          return new Function<String, ListPage<Operation>>() {
 
             @Override public ListPage<Operation> apply(String input) {
-               return api.getZoneOperationApi(projectName, zoneName).listPage(input, options);
+               return api.getOperationApi(projectName).listPageInZone(zoneName, input, options);
             }
          };
       }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java
deleted file mode 100644
index 10fb995..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/GlobalOperationDonePredicate.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.predicates;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
-import org.jclouds.googlecomputeengine.config.UserProject;
-import org.jclouds.googlecomputeengine.domain.Operation;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.inject.Inject;
-
-public final class GlobalOperationDonePredicate implements Predicate<AtomicReference<Operation>> {
-
-   private final GoogleComputeEngineApi api;
-   private final Supplier<String> project;
-
-   @Inject GlobalOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier<String> project) {
-      this.api = api;
-      this.project = project;
-   }
-
-   @Override public boolean apply(AtomicReference<Operation> input) {
-      checkNotNull(input, "input");
-      Operation current = api.getGlobalOperationApi(project.get()).get(input.get().name());
-      switch (current.status()) {
-         case DONE:
-            input.set(current);
-            return true;
-         case PENDING:
-         case RUNNING:
-         default:
-            return false;
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java
deleted file mode 100644
index e8d6535..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/InstancePredicates.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.predicates;
-
-import org.jclouds.googlecomputeengine.domain.templates.InstanceTemplate.PersistentDisk;
-
-import com.google.common.base.Predicate;
-
-public class InstancePredicates {
-
-   public static Predicate<PersistentDisk> isBootDisk() {
-      return new Predicate<PersistentDisk>() {
-         @Override
-         public boolean apply(PersistentDisk input) {
-            return input.boot();
-         }
-      };
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java
deleted file mode 100644
index c63db43..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/NetworkFirewallPredicates.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.predicates;
-
-import static com.google.common.collect.Sets.intersection;
-
-import java.util.List;
-
-import org.jclouds.googlecomputeengine.domain.Firewall;
-import org.jclouds.googlecomputeengine.domain.Firewall.Rule;
-import org.jclouds.net.domain.IpPermission;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-
-public final class NetworkFirewallPredicates {
-
-   public static Predicate<Firewall> hasPortRange(final String protocol, final int fromPort, final int toPort) {
-      return new Predicate<Firewall>() {
-         @Override public boolean apply(Firewall fw) {
-            for (Rule rule : fw.allowed()) {
-               if (!rule.ipProtocol().equals(protocol)) {
-                  continue;
-               }
-               if (rule.ports() == null || rule.ports().isEmpty()) {
-                  return true;
-               }
-               for (String range : rule.ports()) {
-                  if (range.indexOf('-') != -1) {
-                     if (inRange(range, fromPort, toPort)) {
-                        return true;
-                     }
-                  }
-               }
-            }
-            return false;
-         }
-      };
-   }
-
-   private static boolean inRange(String range, int fromPort, int toPort) {
-      List<String> ports = Splitter.on('-').splitToList(range);
-      return fromPort >= Integer.valueOf(ports.get(0)) && toPort <= Integer.valueOf(ports.get(1));
-   }
-
-   public static Predicate<Firewall> hasSourceTag(final String sourceTag) {
-      return new Predicate<Firewall>() {
-         @Override public boolean apply(Firewall input) {
-            return input.sourceTags().contains(sourceTag);
-         }
-      };
-   }
-
-   public static Predicate<Firewall> hasSourceRange(final String sourceRange) {
-      return new Predicate<Firewall>() {
-         @Override  public boolean apply(Firewall input) {
-            return input.sourceRanges().contains(sourceRange);
-         }
-      };
-   }
-
-   public static Predicate<Firewall> equalsIpPermission(final IpPermission permission) {
-      return new Predicate<Firewall>() {
-         @Override public boolean apply(Firewall input) {
-            return Iterables.elementsEqual(permission.getGroupIds(), input.sourceTags())
-                      && Iterables.elementsEqual(permission.getCidrBlocks(), input.sourceRanges())
-                      && (input.allowed().size() == 1
-                             && ruleEqualsIpPermission(permission).apply(Iterables.getOnlyElement(input.allowed())));
-         }
-      };
-   }
-
-   public static Predicate<Firewall> providesIpPermission(final IpPermission permission) {
-      return new Predicate<Firewall>() {
-         @Override  public boolean apply(Firewall input) {
-            boolean groupsMatchTags =
-                  (permission.getGroupIds().isEmpty() && input.sourceTags().isEmpty()) || !intersection(
-                        permission.getGroupIds(), ImmutableSet.copyOf(input.sourceTags())).isEmpty();
-            boolean cidrsMatchRanges =
-                  (permission.getCidrBlocks().isEmpty() && input.sourceRanges().isEmpty()) || !intersection(
-                        permission.getCidrBlocks(), ImmutableSet.copyOf(input.sourceRanges())).isEmpty();
-            boolean firewallHasPorts = hasPortRange(permission.getIpProtocol().value().toLowerCase(),
-                        permission.getFromPort(), permission.getToPort()).apply(input);
-            return groupsMatchTags && cidrsMatchRanges && firewallHasPorts;
-         }
-      };
-   }
-
-   private static Predicate<Firewall.Rule> ruleEqualsIpPermission(final IpPermission permission) {
-      return new Predicate<Rule>() {
-         @Override public boolean apply(Firewall.Rule input) {
-            if (!permission.getIpProtocol().value().toLowerCase().equals(input.ipProtocol())) {
-               return false;
-            }
-            if (input.ports() == null
-                  || input.ports().isEmpty() && permission.getFromPort() == 0 && permission.getToPort() == 0) {
-               return true;
-            } else if (input.ports().size() == 1) {
-               String port = Iterables.getOnlyElement(input.ports());
-               if (permission.getFromPort() == permission.getToPort()) {
-                  return port.equals(String.valueOf(permission.getFromPort()));
-               }
-               return port.equals(permission.getFromPort() + "-" + permission.getToPort());
-            }
-            return false;
-         }
-      };
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java
deleted file mode 100644
index 65c0723..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/RegionOperationDonePredicate.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.predicates;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.inject.Inject;
-
-import org.jclouds.collect.Memoized;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
-import org.jclouds.googlecomputeengine.config.UserProject;
-import org.jclouds.googlecomputeengine.domain.Operation;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-
-public final class RegionOperationDonePredicate implements Predicate<AtomicReference<Operation>> {
-   private final GoogleComputeEngineApi api;
-   private final Supplier<String> project;
-   private final Supplier<Map<URI, String>> selfLinkToName;
-
-   @Inject RegionOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier<String> project,
-         @Memoized Supplier<Map<URI, String>> selfLinkToName) {
-      this.api = api;
-      this.project = project;
-      this.selfLinkToName = selfLinkToName;
-   }
-
-   @Override public boolean apply(AtomicReference<Operation> input) {
-      checkNotNull(input.get(), "input");
-      URI region = checkNotNull(input.get().region(), "region of %s", input.get());
-      String locationId = checkNotNull(selfLinkToName.get().get(region), "location of %s", region);
-      Operation current = api.getRegionOperationApi(project.get(), locationId).get(input.get().name());
-      switch (current.status()) {
-         case DONE:
-            input.set(current);
-            return true;
-         case PENDING:
-         case RUNNING:
-         default:
-            return false;
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java
deleted file mode 100644
index 0081d30..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/predicates/ZoneOperationDonePredicate.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.predicates;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.net.URI;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.jclouds.collect.Memoized;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
-import org.jclouds.googlecomputeengine.config.UserProject;
-import org.jclouds.googlecomputeengine.domain.Operation;
-
-import com.google.common.base.Predicate;
-import com.google.common.base.Supplier;
-import com.google.inject.Inject;
-
-/**
- * Tests that a Zone Operation is done, returning the completed Operation when it is.
- */
-public final class ZoneOperationDonePredicate implements Predicate<AtomicReference<Operation>> {
-
-   private final GoogleComputeEngineApi api;
-   private final Supplier<String> project;
-   private final Supplier<Map<URI, String>> selfLinkToName;
-
-   @Inject ZoneOperationDonePredicate(GoogleComputeEngineApi api, @UserProject Supplier<String> project,
-         @Memoized Supplier<Map<URI, String>> selfLinkToName) {
-      this.api = api;
-      this.project = project;
-      this.selfLinkToName = selfLinkToName;
-   }
-
-   @Override public boolean apply(AtomicReference<Operation> input) {
-      checkNotNull(input.get(), "input");
-      URI zone = checkNotNull(input.get().zone(), "zone of %s", input.get());
-      String locationId = checkNotNull(selfLinkToName.get().get(zone), "location of %s", zone);
-      Operation current = api.getZoneOperationApi(project.get(), locationId).get(input.get().name());
-      switch (current.status()) {
-         case DONE:
-            input.set(current);
-            return true;
-         case PENDING:
-         case RUNNING:
-         default:
-            return false;
-      }
-   }
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java
index 3018c1e..6549823 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceExpectTest.java
@@ -25,8 +25,6 @@ import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_B
 import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_PROJECTS;
 import static org.jclouds.googlecomputeengine.domain.Instance.Status.RUNNING;
 import static org.jclouds.googlecomputeengine.domain.Instance.Status.TERMINATED;
-import static org.jclouds.googlecomputeengine.features.GlobalOperationApiExpectTest.GET_GLOBAL_OPERATION_REQUEST;
-import static org.jclouds.googlecomputeengine.features.GlobalOperationApiExpectTest.GET_GLOBAL_OPERATION_RESPONSE;
 import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_CENTOS_IMAGES_REQUEST;
 import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_CENTOS_IMAGES_RESPONSE;
 import static org.jclouds.googlecomputeengine.features.ImageApiExpectTest.LIST_DEBIAN_IMAGES_REQUEST;
@@ -45,8 +43,6 @@ import static org.jclouds.googlecomputeengine.features.NetworkApiExpectTest.GET_
 import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_REQUEST;
 import static org.jclouds.googlecomputeengine.features.ProjectApiExpectTest.GET_PROJECT_RESPONSE;
 import static org.jclouds.googlecomputeengine.features.RegionApiExpectTest.LIST_REGIONS_REQ;
-import static org.jclouds.googlecomputeengine.features.ZoneOperationApiExpectTest.GET_ZONE_OPERATION_REQUEST;
-import static org.jclouds.googlecomputeengine.features.ZoneOperationApiExpectTest.GET_ZONE_OPERATION_RESPONSE;
 import static org.jclouds.util.Strings2.toStringAndClose;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
@@ -77,6 +73,17 @@ import com.google.common.collect.ImmutableSet;
 
 @Test(groups = "unit", testName = "GoogleComputeEngineServiceExpectTest")
 public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngineServiceExpectTest {
+   private static final String OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/zones/us-central1-a/operations";
+
+   private static final HttpRequest GET_ZONE_OPERATION_REQUEST = HttpRequest
+           .builder()
+           .method("GET")
+           .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb")
+           .addHeader("Accept", "application/json")
+           .addHeader("Authorization", "Bearer " + TOKEN).build();
+
+   private static final HttpResponse GET_ZONE_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200)
+           .payload(staticPayloadFromResource("/zone_operation.json")).build();
 
    private HttpRequest INSERT_NETWORK_REQUEST = HttpRequest
            .builder()
@@ -339,9 +346,9 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin
               .add(getNetworkRequest)
               .add(listFirewallsRequest)
               .add(deleteFirewallRequest)
-              .add(GET_GLOBAL_OPERATION_REQUEST)
+              .add(GET_ZONE_OPERATION_REQUEST)
               .add(deleteNetworkReqquest)
-              .add(GET_GLOBAL_OPERATION_REQUEST)
+              .add(GET_ZONE_OPERATION_REQUEST)
               .build();
 
       List<HttpResponse> orderedResponses = ImmutableList.<HttpResponse>builder()
@@ -365,9 +372,9 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin
               .add(getNetworkResponse)
               .add(listFirewallsResponse)
               .add(SUCCESSFUL_OPERATION_RESPONSE)
-              .add(GET_GLOBAL_OPERATION_RESPONSE)
+              .add(GET_ZONE_OPERATION_RESPONSE)
               .add(SUCCESSFUL_OPERATION_RESPONSE)
-              .add(GET_GLOBAL_OPERATION_RESPONSE)
+              .add(GET_ZONE_OPERATION_RESPONSE)
               .build();
 
       ComputeService client = orderedRequestsSendResponses(orderedRequests, orderedResponses);
@@ -375,7 +382,6 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin
    }
 
    public void listAssignableLocations() throws Exception {
-
       ImmutableMap<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.
               <HttpRequest, HttpResponse>builder()
               .put(requestForScopes(COMPUTE_READONLY_SCOPE), TOKEN_RESPONSE)
@@ -478,11 +484,11 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin
               .add(GET_NETWORK_REQUEST)
               .add(requestForScopes(COMPUTE_SCOPE))
               .add(INSERT_NETWORK_REQUEST)
-              .add(GET_GLOBAL_OPERATION_REQUEST)
+              .add(GET_ZONE_OPERATION_REQUEST)
               .add(GET_NETWORK_REQUEST)
               .add(getFirewallRequest)
               .add(insertFirewallRequest)
-              .add(GET_GLOBAL_OPERATION_REQUEST)
+              .add(GET_ZONE_OPERATION_REQUEST)
               .add(LIST_INSTANCES_REQUEST)
               .add(createDiskRequestForInstance("test-1"))
               .add(GET_ZONE_OPERATION_REQUEST)
@@ -512,11 +518,11 @@ public class GoogleComputeEngineServiceExpectTest extends BaseGoogleComputeEngin
               .add(HttpResponse.builder().statusCode(404).build())
               .add(TOKEN_RESPONSE)
               .add(SUCCESSFUL_OPERATION_RESPONSE)
-              .add(GET_GLOBAL_OPERATION_RESPONSE)
+              .add(GET_ZONE_OPERATION_RESPONSE)
               .add(GET_NETWORK_RESPONSE)
               .add(HttpResponse.builder().statusCode(404).build())
               .add(SUCCESSFUL_OPERATION_RESPONSE)
-              .add(GET_GLOBAL_OPERATION_RESPONSE)
+              .add(GET_ZONE_OPERATION_RESPONSE)
               .add(LIST_INSTANCES_RESPONSE)
               .add(SUCCESSFUL_OPERATION_RESPONSE)
               .add(GET_ZONE_OPERATION_RESPONSE)

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeededTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeededTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeededTest.java
index 101758f..dcbd1bc 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeededTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeededTest.java
@@ -26,16 +26,16 @@ import java.net.URI;
 
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
+import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone;
 import org.jclouds.googlecomputeengine.config.UserProject;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.features.GlobalOperationApi;
 import org.jclouds.googlecomputeengine.features.NetworkApi;
 import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationTest;
-import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate;
 import org.testng.annotations.Test;
 
 import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
 import com.google.inject.Provides;
@@ -48,7 +48,7 @@ public class CreateNetworkIfNeededTest {
    public void testApply() {
       GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
       NetworkApi nwApi = createMock(NetworkApi.class);
-      GlobalOperationApi globalApi = createMock(GlobalOperationApi.class);
+      ResourceFunctions resources = createMock(ResourceFunctions.class);
 
       Network network = Network.create( //
             "abcd", // id
@@ -61,38 +61,32 @@ public class CreateNetworkIfNeededTest {
 
       Operation createOp = new ParseGlobalOperationTest().expected();
 
-      Supplier<String> userProject = new Supplier<String>() {
-         @Override
-         public String get() {
-            return "myproject";
-         }
-      };
+      Supplier<String> userProject = Suppliers.ofInstance("myproject");
 
       expect(api.getNetworkApi(userProject.get())).andReturn(nwApi).atLeastOnce();
-      expect(api.getGlobalOperationApi(userProject.get())).andReturn(globalApi).atLeastOnce();
 
       expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")) .andReturn(createOp);
-      expect(globalApi.get(createOp.name())).andReturn(createOp);
+      expect(resources.operation(createOp.selfLink())).andReturn(createOp);
       expect(nwApi.get("this-network")).andReturn(null);
       expect(nwApi.get("this-network")).andReturn(network);
 
-      replay(api, nwApi, globalApi);
+      replay(api, nwApi, resources);
 
       NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", null);
 
-      GlobalOperationDonePredicate pred = globalOperationDonePredicate(api, userProject);
+      AtomicOperationDone pred = atomicOperationDone(api, resources);
 
-      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l);
+      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred);
 
       assertEquals(creator.apply(input), network);
 
-      verify(api, nwApi, globalApi);
+      verify(api, nwApi, resources);
    }
 
    public void testApplyWithGateway() {
       GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
       NetworkApi nwApi = createMock(NetworkApi.class);
-      GlobalOperationApi globalApi = createMock(GlobalOperationApi.class);
+      ResourceFunctions resources = createMock(ResourceFunctions.class);
 
       Network network = Network.create( //
             "abcd", // id
@@ -105,44 +99,39 @@ public class CreateNetworkIfNeededTest {
 
       Operation createOp = new ParseGlobalOperationTest().expected();
 
-      Supplier<String> userProject = new Supplier<String>() {
-         @Override
-         public String get() {
-            return "myproject";
-         }
-      };
+      Supplier<String> userProject = Suppliers.ofInstance("myproject");
 
       expect(api.getNetworkApi(userProject.get())).andReturn(nwApi).atLeastOnce();
-      expect(api.getGlobalOperationApi(userProject.get())).andReturn(globalApi).atLeastOnce();
 
       expect(nwApi.createInIPv4RangeWithGateway("this-network", "0.0.0.0/0", "1.2.3.4")).andReturn(createOp);
-      expect(globalApi.get(createOp.name())).andReturn(createOp);
+      expect(resources.operation(createOp.selfLink())).andReturn(createOp);
       expect(nwApi.get("this-network")).andReturn(null);
       expect(nwApi.get("this-network")).andReturn(network);
 
-      replay(api, nwApi, globalApi);
+      replay(api, nwApi, resources);
 
       NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", "1.2.3.4");
 
-      GlobalOperationDonePredicate pred = globalOperationDonePredicate(api, userProject);
+      AtomicOperationDone pred = atomicOperationDone(api, resources);
 
-      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l);
+      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred);
 
       assertEquals(creator.apply(input), network);
 
-      verify(api, nwApi, globalApi);
+      verify(api, nwApi, resources);
    }
 
-   private GlobalOperationDonePredicate globalOperationDonePredicate(final GoogleComputeEngineApi api,
-         final Supplier<String> userProject) {
+   private AtomicOperationDone atomicOperationDone(final GoogleComputeEngineApi api,
+         final ResourceFunctions resources) {
       return Guice.createInjector(new AbstractModule() { // Rather than opening ctor public
          @Override protected void configure() {
             bind(GoogleComputeEngineApi.class).toInstance(api);
+            bind(ResourceFunctions.class).toInstance(resources);
          }
 
          @Provides @UserProject Supplier<String> project() {
-            return userProject;
+            return Suppliers.ofInstance("myproject");
          }
-      }).getInstance(GlobalOperationDonePredicate.class);
+      }).getInstance(AtomicOperationDone.class);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreateTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreateTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreateTest.java
index 3037a5e..068446f 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreateTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/FindNetworkOrCreateTest.java
@@ -23,27 +23,29 @@ import static org.easymock.EasyMock.verify;
 import static org.testng.Assert.assertEquals;
 
 import java.net.URI;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
-import org.jclouds.googlecomputeengine.config.UserProject;
+import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone;
 import org.jclouds.googlecomputeengine.domain.Network;
 import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.features.GlobalOperationApi;
 import org.jclouds.googlecomputeengine.features.NetworkApi;
 import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationTest;
-import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate;
 import org.testng.annotations.Test;
 
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
 import com.google.common.cache.CacheBuilder;
 import com.google.common.cache.LoadingCache;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
-import com.google.inject.Provides;
 
 @Test
 public class FindNetworkOrCreateTest {
+   private static final Supplier<String> USER_PROJECT = Suppliers.ofInstance("myproject");
    private static final String BASE_URL = "https://www.googleapis.com/compute/v1/projects";
    private static final Network NETWORK = Network.create( //
          "abcd", // id
@@ -58,14 +60,7 @@ public class FindNetworkOrCreateTest {
       GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
       NetworkApi nwApi = createMock(NetworkApi.class);
 
-      Supplier<String> userProject = new Supplier<String>() {
-         @Override
-         public String get() {
-            return "myproject";
-         }
-      };
-
-      expect(api.getNetworkApi(userProject.get())).andReturn(nwApi).atLeastOnce();
+      expect(api.getNetworkApi(USER_PROJECT.get())).andReturn(nwApi).atLeastOnce();
 
       expect(nwApi.get("this-network")).andReturn(NETWORK);
 
@@ -73,11 +68,11 @@ public class FindNetworkOrCreateTest {
 
       NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", null);
 
-      GlobalOperationDonePredicate pred = globalOperationDonePredicate(api, userProject);
+      Predicate<AtomicReference<Operation>> operationDone = Predicates.alwaysFalse(); // No op should be created!
 
-      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l);
+      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, USER_PROJECT, operationDone);
 
-      FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, userProject);
+      FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, USER_PROJECT);
 
       LoadingCache<NetworkAndAddressRange, Network> cache = CacheBuilder.newBuilder().build(loader);
 
@@ -92,36 +87,28 @@ public class FindNetworkOrCreateTest {
    public void testLoadNew() {
       GoogleComputeEngineApi api = createMock(GoogleComputeEngineApi.class);
       NetworkApi nwApi = createMock(NetworkApi.class);
-      GlobalOperationApi globalApi = createMock(GlobalOperationApi.class);
+      ResourceFunctions resources = createMock(ResourceFunctions.class);
 
       Operation createOp = new ParseGlobalOperationTest().expected();
 
-      Supplier<String> userProject = new Supplier<String>() {
-         @Override
-         public String get() {
-            return "myproject";
-         }
-      };
-
-      expect(api.getNetworkApi(userProject.get())).andReturn(nwApi).atLeastOnce();
-      expect(api.getGlobalOperationApi(userProject.get())).andReturn(globalApi).atLeastOnce();
+      expect(api.getNetworkApi(USER_PROJECT.get())).andReturn(nwApi).atLeastOnce();
 
       expect(nwApi.createInIPv4Range("this-network", "0.0.0.0/0")).andReturn(createOp);
-      expect(globalApi.get(createOp.name())).andReturn(createOp);
+      expect(resources.operation(createOp.selfLink())).andReturn(createOp);
       // pre-creation
       expect(nwApi.get("this-network")).andReturn(null).times(2);
       // post-creation
       expect(nwApi.get("this-network")).andReturn(NETWORK);
 
-      replay(api, nwApi, globalApi);
+      replay(api, nwApi, resources);
 
       NetworkAndAddressRange input = NetworkAndAddressRange.create("this-network", "0.0.0.0/0", null);
 
-      GlobalOperationDonePredicate pred = globalOperationDonePredicate(api, userProject);
+      AtomicOperationDone pred = atomicOperationDone(resources);
 
-      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, userProject, pred, 100l, 100l);
+      CreateNetworkIfNeeded creator = new CreateNetworkIfNeeded(api, USER_PROJECT, pred);
 
-      FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, userProject);
+      FindNetworkOrCreate loader = new FindNetworkOrCreate(api, creator, USER_PROJECT);
 
       LoadingCache<NetworkAndAddressRange, Network> cache = CacheBuilder.newBuilder().build(loader);
 
@@ -130,20 +117,15 @@ public class FindNetworkOrCreateTest {
       // Second call is to ensure we only need to make the API calls once.
       assertEquals(cache.getUnchecked(input), NETWORK);
 
-      verify(api, nwApi, globalApi);
+      verify(api, nwApi, resources);
    }
 
-   private GlobalOperationDonePredicate globalOperationDonePredicate(final GoogleComputeEngineApi api,
-         final Supplier<String> userProject) {
+   private AtomicOperationDone atomicOperationDone(final ResourceFunctions resources) {
       return Guice.createInjector(new AbstractModule() { // Rather than opening ctor public
          @Override protected void configure() {
-            bind(GoogleComputeEngineApi.class).toInstance(api);
-         }
-
-         @Provides @UserProject Supplier<String> project() {
-            return userProject;
+            bind(ResourceFunctions.class).toInstance(resources);
          }
-      }).getInstance(GlobalOperationDonePredicate.class);
+      }).getInstance(AtomicOperationDone.class);
    }
 }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java
index 959ce15..d4df1e5 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/GoogleComputeEngineImageToImageTest.java
@@ -27,7 +27,7 @@ import org.testng.annotations.Test;
 
 @Test(groups = "unit", testName = "GoogleComputeEngineImageToImageTest")
 public class GoogleComputeEngineImageToImageTest {
-   public void testArbitratyImageName() {
+   public void testArbitraryImageName() {
       GoogleComputeEngineImageToImage imageToImage = new GoogleComputeEngineImageToImage();
       Image image = image("arbitratyname");
       org.jclouds.compute.domain.Image transformed = imageToImage.apply(image);

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java
index 891a5a9..933487f 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/NetworkToSecurityGroupTest.java
@@ -39,6 +39,7 @@ import org.testng.annotations.Test;
 
 import com.google.common.base.Predicates;
 import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
@@ -46,12 +47,7 @@ public class NetworkToSecurityGroupTest {
 
    @Test
    public void testApply() {
-      Supplier<String> projectSupplier = new Supplier<String>() {
-         @Override
-         public String get() {
-            return "myproject";
-         }
-      };
+      Supplier<String> projectSupplier = Suppliers.ofInstance("myproject");
 
       FirewallToIpPermission fwToPerm = new FirewallToIpPermission();
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java
index cb48943..c15dacc 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/compute/functions/OrphanedGroupsFromDeadNodesTest.java
@@ -36,6 +36,8 @@ import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
 
 public class OrphanedGroupsFromDeadNodesTest {
 
@@ -67,8 +69,8 @@ public class OrphanedGroupsFromDeadNodesTest {
 
       replay(mock);
 
-      OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(new
-              AllNodesInGroupTerminated(mock));
+      OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(
+              allNodesInGroupTerminated(mock));
 
       Set<String> orphanedGroups = orphanedGroupsFromDeadNodes.apply(allDeadNodes);
 
@@ -96,8 +98,8 @@ public class OrphanedGroupsFromDeadNodesTest {
 
       replay(mock);
 
-      OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(new
-              AllNodesInGroupTerminated(mock));
+      OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(
+            allNodesInGroupTerminated(mock));
 
       Set<String> orphanedGroups = orphanedGroupsFromDeadNodes.apply(allDeadNodes);
 
@@ -125,12 +127,20 @@ public class OrphanedGroupsFromDeadNodesTest {
 
       replay(mock);
 
-      OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(new
-              AllNodesInGroupTerminated(mock));
+      OrphanedGroupsFromDeadNodes orphanedGroupsFromDeadNodes = new OrphanedGroupsFromDeadNodes(
+              allNodesInGroupTerminated(mock));
 
       Set<String> orphanedGroups = orphanedGroupsFromDeadNodes.apply(allDeadNodes);
 
       assertSame(orphanedGroups.size(), 1);
       assertTrue(orphanedGroups.contains("1"));
    }
+
+   private Predicate<String> allNodesInGroupTerminated(final ComputeService mock) {
+      return Guice.createInjector(new AbstractModule() {
+         @Override protected void configure() {
+            bind(ComputeService.class).toInstance(mock);
+         }
+      }).getInstance(AllNodesInGroupTerminated.class); // rather than opening ctor.
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java
index f076687..d5f71a8 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/AddressApiLiveTest.java
@@ -30,7 +30,6 @@ import org.testng.annotations.Test;
 public class AddressApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    private static final String ADDRESS_NAME = "address-api-live-test-address";
-   private static final int TIME_WAIT = 30;
 
    private AddressApi api() {
       return api.getAddressApi(userProject.get(), DEFAULT_REGION_NAME);
@@ -38,8 +37,7 @@ public class AddressApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertAddress() {
-
-      assertRegionOperationDoneSucessfully(api().create(ADDRESS_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().create(ADDRESS_NAME));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertAddress")
@@ -51,14 +49,12 @@ public class AddressApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testGetAddress")
    public void testListAddress() {
-
       Iterator<ListPage<Address>> addresses = api().list(filter("name eq " + ADDRESS_NAME));
       assertEquals(addresses.next().size(), 1);
    }
 
    @Test(groups = "live", dependsOnMethods = "testListAddress")
    public void testDeleteAddress() {
-
-      assertRegionOperationDoneSucessfully(api().delete(ADDRESS_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(ADDRESS_NAME));
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java
index ad771d9..8b61648 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/DiskApiLiveTest.java
@@ -34,7 +34,6 @@ public class DiskApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    public static final String DISK_NAME = "disk-api-live-test-disk";
    public static final String SSD_DISK_NAME = "disk-api-live-test-disk-ssd";
-   public static final int TIME_WAIT = 30;
    public static final int sizeGb = 1;
 
    private DiskApi api() {
@@ -43,7 +42,7 @@ public class DiskApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertDisk() {
-      assertZoneOperationDoneSuccessfully(api().create(DISK_NAME, sizeGb), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().create(DISK_NAME, sizeGb));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertDisk")
@@ -66,7 +65,7 @@ public class DiskApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testListDisk")
    public void testDeleteDisk() {
-      assertZoneOperationDoneSuccessfully(api().delete(DISK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(DISK_NAME));
    }
 
    private void assertDiskEquals(Disk result) {
@@ -79,7 +78,7 @@ public class DiskApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    public void testInsertSSDDisk() {
       URI diskType = getDiskTypeUrl(userProject.get(), DEFAULT_ZONE_NAME, "pd-ssd");
       DiskCreationOptions diskCreationOptions = new DiskCreationOptions().type(diskType);
-      assertZoneOperationDoneSuccessfully(api().create(SSD_DISK_NAME, sizeGb, diskCreationOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().create(SSD_DISK_NAME, sizeGb, diskCreationOptions));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertSSDDisk")
@@ -91,7 +90,7 @@ public class DiskApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testGetSSDDisk")
    public void testDeleteSSDDisk() {
-      assertZoneOperationDoneSuccessfully(api().delete(SSD_DISK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(SSD_DISK_NAME));
    }
 
    private void assertSSDDiskEquals(Disk result) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
index 6cc6ec7..0d7371a 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/FirewallApiLiveTest.java
@@ -22,7 +22,6 @@ import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
 import java.util.Iterator;
-import java.util.List;
 
 import org.jclouds.googlecomputeengine.domain.Firewall;
 import org.jclouds.googlecomputeengine.domain.ListPage;
@@ -38,7 +37,6 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
    private static final String FIREWALL_NAME = "firewall-api-live-test-firewall";
    private static final String FIREWALL_NETWORK_NAME = "firewall-api-live-test-network";
    private static final String IPV4_RANGE = "10.0.0.0/8";
-   private static final int TIME_WAIT = 30;
 
    private FirewallApi api() {
       return api.getFirewallApi(userProject.get());
@@ -46,10 +44,9 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live")
    public void testInsertFirewall() {
-
       // need to insert the network first
-      assertGlobalOperationDoneSucessfully(api.getNetworkApi(userProject.get()).createInIPv4Range
-              (FIREWALL_NETWORK_NAME, IPV4_RANGE), TIME_WAIT);
+      assertOperationDoneSuccessfully(
+            api.getNetworkApi(userProject.get()).createInIPv4Range(FIREWALL_NETWORK_NAME, IPV4_RANGE));
 
       FirewallOptions firewall = new FirewallOptions()
               .addAllowedRule(Firewall.Rule.create("tcp", ImmutableList.of("22")))
@@ -57,13 +54,12 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
               .addSourceTag("tag1")
               .addTargetTag("tag2");
 
-      assertGlobalOperationDoneSucessfully(api().createInNetwork(FIREWALL_NAME, getNetworkUrl(userProject.get(),
-              FIREWALL_NETWORK_NAME), firewall), TIME_WAIT);
+      assertOperationDoneSuccessfully(
+            api().createInNetwork(FIREWALL_NAME, getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME), firewall));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertFirewall")
    public void testUpdateFirewall() {
-
       FirewallOptions firewall = new FirewallOptions()
               .name(FIREWALL_NAME)
               .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME))
@@ -72,12 +68,11 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
               .addTargetTag("tag2")
               .allowedRules(ImmutableList.of(Firewall.Rule.create("tcp", ImmutableList.of("23"))));
 
-      assertGlobalOperationDoneSucessfully(api().update(FIREWALL_NAME, firewall), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().update(FIREWALL_NAME, firewall));
    }
 
    @Test(groups = "live", dependsOnMethods = "testUpdateFirewall")
    public void testPatchFirewall() {
-
       FirewallOptions firewall = new FirewallOptions()
               .name(FIREWALL_NAME)
               .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME))
@@ -87,12 +82,11 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
               .addSourceTag("tag1")
               .addTargetTag("tag2");
 
-      assertGlobalOperationDoneSucessfully(api().update(FIREWALL_NAME, firewall), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().update(FIREWALL_NAME, firewall));
    }
 
    @Test(groups = "live", dependsOnMethods = "testPatchFirewall")
    public void testGetFirewall() {
-
       FirewallOptions patchedFirewall = new FirewallOptions()
               .name(FIREWALL_NAME)
               .network(getNetworkUrl(userProject.get(), FIREWALL_NETWORK_NAME))
@@ -109,20 +103,15 @@ public class FirewallApiLiveTest extends BaseGoogleComputeEngineApiLiveTest {
 
    @Test(groups = "live", dependsOnMethods = "testGetFirewall")
    public void testListFirewall() {
-
       Iterator<ListPage<Firewall>> firewalls = api().list(filter("name eq " + FIREWALL_NAME));
 
-      List<Firewall> firewallsAsList = firewalls.next();
-
-      assertEquals(firewallsAsList.size(), 1);
+      assertEquals(firewalls.next().size(), 1);
    }
 
    @Test(groups = "live", dependsOnMethods = "testListFirewall")
    public void testDeleteFirewall() {
-
-      assertGlobalOperationDoneSucessfully(api().delete(FIREWALL_NAME), TIME_WAIT);
-      assertGlobalOperationDoneSucessfully(api.getNetworkApi(userProject.get()).delete
-              (FIREWALL_NETWORK_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(FIREWALL_NAME));
+      assertOperationDoneSuccessfully(api.getNetworkApi(userProject.get()).delete(FIREWALL_NETWORK_NAME));
    }
 
    private void assertFirewallEquals(Firewall result, FirewallOptions expected) {

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ForwardingRuleApiLiveTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ForwardingRuleApiLiveTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ForwardingRuleApiLiveTest.java
index 9b361ee..20b2334 100644
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ForwardingRuleApiLiveTest.java
+++ b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/ForwardingRuleApiLiveTest.java
@@ -38,7 +38,6 @@ public class ForwardingRuleApiLiveTest extends BaseGoogleComputeEngineApiLiveTes
    private static final String TARGETPOOL_NAME_NEW = "forwarding-rule-api-live-test-new-targetpool";
    private static final String DESCRIPTION = "Forwarding rule api live test forwarding rule.";
    private static final String ADDRESS_NAME = "forwarding-rule-api-address";
-   private static final int TIME_WAIT = 30;
    private TargetPool targetPool;
    private TargetPool newTargetPool;
    private Address address;
@@ -62,21 +61,21 @@ public class ForwardingRuleApiLiveTest extends BaseGoogleComputeEngineApiLiveTes
    @BeforeClass
    public void init() {
       TargetPoolCreationOptions targetPoolCreationOptions = new TargetPoolCreationOptions();
-      assertRegionOperationDoneSucessfully(targetPoolApi().create(TARGETPOOL_NAME, targetPoolCreationOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(targetPoolApi().create(TARGETPOOL_NAME, targetPoolCreationOptions));
       targetPool = targetPoolApi().get(TARGETPOOL_NAME);
 
-      assertRegionOperationDoneSucessfully(targetPoolApi().create(TARGETPOOL_NAME_NEW, targetPoolCreationOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(targetPoolApi().create(TARGETPOOL_NAME_NEW, targetPoolCreationOptions));
       newTargetPool = targetPoolApi().get(TARGETPOOL_NAME_NEW);
 
-      assertRegionOperationDoneSucessfully(addressApi().create(ADDRESS_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(addressApi().create(ADDRESS_NAME));
       address = addressApi().get(ADDRESS_NAME);
    }
 
    @AfterClass
    public void tearDown() {
-      assertRegionOperationDoneSucessfully(targetPoolApi().delete(TARGETPOOL_NAME), TIME_WAIT);
-      assertRegionOperationDoneSucessfully(targetPoolApi().delete(TARGETPOOL_NAME_NEW), TIME_WAIT);
-      assertRegionOperationDoneSucessfully(addressApi().delete(ADDRESS_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(targetPoolApi().delete(TARGETPOOL_NAME));
+      assertOperationDoneSuccessfully(targetPoolApi().delete(TARGETPOOL_NAME_NEW));
+      assertOperationDoneSuccessfully(addressApi().delete(ADDRESS_NAME));
    }
 
    @Test(groups = "live")
@@ -86,7 +85,7 @@ public class ForwardingRuleApiLiveTest extends BaseGoogleComputeEngineApiLiveTes
                                                                            .ipAddress(address.address())
                                                                            .ipProtocol(ForwardingRule.IPProtocol.TCP)
                                                                            .target(targetPool.selfLink());
-      assertRegionOperationDoneSucessfully(api().create(FORWARDING_RULE_NAME, forwardingRuleCreationOptions), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().create(FORWARDING_RULE_NAME, forwardingRuleCreationOptions));
    }
 
    @Test(groups = "live", dependsOnMethods = "testInsertForwardingRule")
@@ -102,7 +101,7 @@ public class ForwardingRuleApiLiveTest extends BaseGoogleComputeEngineApiLiveTes
 
    @Test(groups = "live", dependsOnMethods = "testGetForwardingRule")
    public void testSetTargetForwardingRule(){
-      assertRegionOperationDoneSucessfully(api().setTarget(FORWARDING_RULE_NAME, newTargetPool.selfLink()), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().setTarget(FORWARDING_RULE_NAME, newTargetPool.selfLink()));
       ForwardingRule forwardingRule = api().get(FORWARDING_RULE_NAME);
       assertNotNull(forwardingRule);
       assertEquals(forwardingRule.name(), FORWARDING_RULE_NAME);
@@ -117,6 +116,6 @@ public class ForwardingRuleApiLiveTest extends BaseGoogleComputeEngineApiLiveTes
 
    @Test(groups = "live", dependsOnMethods = {"testListForwardingRule", "testSetTargetForwardingRule"}, alwaysRun = true)
    public void testDeleteForwardingRule() {
-      assertRegionOperationDoneSucessfully(api().delete(FORWARDING_RULE_NAME), TIME_WAIT);
+      assertOperationDoneSuccessfully(api().delete(FORWARDING_RULE_NAME));
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java b/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java
deleted file mode 100644
index 8209741..0000000
--- a/google-compute-engine/src/test/java/org/jclouds/googlecomputeengine/features/GlobalOperationApiExpectTest.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
-import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertNull;
-
-import org.jclouds.googlecomputeengine.internal.BaseGoogleComputeEngineApiExpectTest;
-import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationListTest;
-import org.jclouds.googlecomputeengine.parse.ParseGlobalOperationTest;
-import org.jclouds.http.HttpRequest;
-import org.jclouds.http.HttpResponse;
-import org.testng.annotations.Test;
-
-@Test(groups = "unit", testName = "GlobalOperationApiExpectTest")
-public class GlobalOperationApiExpectTest extends BaseGoogleComputeEngineApiExpectTest {
-
-   private static final String OPERATIONS_URL_PREFIX = BASE_URL + "/myproject/global/operations";
-
-   public static final HttpRequest GET_GLOBAL_OPERATION_REQUEST = HttpRequest
-           .builder()
-           .method("GET")
-           .endpoint(OPERATIONS_URL_PREFIX + "/operation-1354084865060-4cf88735faeb8-bbbb12cb")
-           .addHeader("Accept", "application/json")
-           .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-   public static final HttpResponse GET_GLOBAL_OPERATION_RESPONSE = HttpResponse.builder().statusCode(200)
-           .payload(staticPayloadFromResource("/global_operation.json")).build();
-
-   public void testGetOperationResponseIs2xx() throws Exception {
-
-      GlobalOperationApi operationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, GET_GLOBAL_OPERATION_REQUEST, GET_GLOBAL_OPERATION_RESPONSE).getGlobalOperationApi("myproject");
-
-      assertEquals(operationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb"),
-              new ParseGlobalOperationTest().expected());
-   }
-
-   public void testGetOperationResponseIs4xx() throws Exception {
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, GET_GLOBAL_OPERATION_REQUEST, operationResponse).getGlobalOperationApi("myproject");
-
-      assertNull(globalOperationApi.get("operation-1354084865060-4cf88735faeb8-bbbb12cb"));
-   }
-
-   public void testDeleteOperationResponseIs2xx() throws Exception {
-      HttpRequest delete = HttpRequest
-              .builder()
-              .method("DELETE")
-              .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(204).build();
-
-      GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
-              TOKEN_RESPONSE, delete, operationResponse).getGlobalOperationApi("myproject");
-
-      globalOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
-   }
-
-   public void testDeleteOperationResponseIs4xx() throws Exception {
-      HttpRequest delete = HttpRequest
-              .builder()
-              .method("DELETE")
-              .endpoint(OPERATIONS_URL_PREFIX + "/operation-1352178598164-4cdcc9d031510-4aa46279")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_SCOPE),
-              TOKEN_RESPONSE, delete, operationResponse).getGlobalOperationApi("myproject");
-
-      globalOperationApi.delete("operation-1352178598164-4cdcc9d031510-4aa46279");
-   }
-
-   public void testLisOperationWithNoOptionsResponseIs2xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX)
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
-              .payload(payloadFromResource("/global_operation_list.json")).build();
-
-      GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getGlobalOperationApi("myproject");
-
-      assertEquals(globalOperationApi.list().next().toString(),
-              new ParseGlobalOperationListTest().expected().toString());
-   }
-
-   public void testListOperationWithPaginationOptionsResponseIs2xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX +
-                      "?pageToken=CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcG" +
-                      "VyYXRpb24tMTM1MjI0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz&" +
-                      "filter=" +
-                      "status%20eq%20done&" +
-                      "maxResults=3")
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(200)
-              .payload(payloadFromResource("/global_operation_list.json")).build();
-
-      GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getGlobalOperationApi("myproject");
-
-      assertEquals(globalOperationApi.listPage("CglPUEVSQVRJT04SOzU5MDQyMTQ4Nzg1Mi5vcGVyYXRpb24tMTM1Mj" +
-              "I0NDI1ODAzMC00Y2RkYmU2YTJkNmIwLWVkMzIyMzQz",
-              filter("status eq done").maxResults(3)).toString(),
-              new ParseGlobalOperationListTest().expected().toString());
-   }
-
-   public void testListOperationWithPaginationOptionsResponseIs4xx() {
-      HttpRequest get = HttpRequest
-              .builder()
-              .method("GET")
-              .endpoint(OPERATIONS_URL_PREFIX)
-              .addHeader("Accept", "application/json")
-              .addHeader("Authorization", "Bearer " + TOKEN).build();
-
-      HttpResponse operationResponse = HttpResponse.builder().statusCode(404).build();
-
-      GlobalOperationApi globalOperationApi = requestsSendResponses(requestForScopes(COMPUTE_READONLY_SCOPE),
-              TOKEN_RESPONSE, get, operationResponse).getGlobalOperationApi("myproject");
-
-      assertFalse(globalOperationApi.list().hasNext());
-   }
-}


[5/5] jclouds-labs-google git commit: Consolidate operation state management.

Posted by ad...@apache.org.
Consolidate operation state management.


Project: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/commit/8895953d
Tree: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/tree/8895953d
Diff: http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/diff/8895953d

Branch: refs/heads/master
Commit: 8895953d149abfd9bc2256d94df70fe07850a64a
Parents: 867c785
Author: Adrian Cole <ac...@twitter.com>
Authored: Thu Nov 6 17:42:13 2014 -0800
Committer: Adrian Cole <ac...@twitter.com>
Committed: Fri Nov 7 07:57:33 2014 -0800

----------------------------------------------------------------------
 google-compute-engine/pom.xml                   |   1 +
 .../GoogleComputeEngineApi.java                 |  51 +---
 .../compute/GoogleComputeEngineService.java     |  34 +--
 .../GoogleComputeEngineServiceAdapter.java      |  71 ++---
 ...GoogleComputeEngineServiceContextModule.java |  23 ++
 ...ogleComputeEngineSecurityGroupExtension.java |  41 ++-
 .../functions/CreateNetworkIfNeeded.java        |  31 +-
 .../functions/FirewallTagNamingConvention.java  |   8 +-
 .../compute/functions/ResourceFunctions.java    |  55 ++++
 .../predicates/AllNodesInGroupTerminated.java   |  13 +-
 .../predicates/AtomicInstanceVisible.java       |  44 +++
 .../compute/predicates/AtomicOperationDone.java |  53 ++++
 .../predicates/NetworkFirewallPredicates.java   | 125 ++++++++
 ...desWithGroupEncodedIntoNameThenAddToSet.java |  26 +-
 .../GoogleComputeEngineHttpApiModule.java       |  21 --
 .../googlecomputeengine/domain/Tags.java        |   4 +-
 .../features/AddressApi.java                    |   2 +-
 .../features/FirewallApi.java                   |   6 +-
 .../features/GlobalOperationApi.java            | 110 -------
 .../features/InstanceApi.java                   |   4 +-
 .../features/NetworkApi.java                    |   4 +-
 .../features/OperationApi.java                  | 198 +++++++++++++
 .../features/RegionOperationApi.java            | 110 -------
 .../googlecomputeengine/features/RouteApi.java  |   2 +-
 .../features/ZoneOperationApi.java              | 110 -------
 .../BaseWithRegionToIteratorOfListPage.java     |   2 +-
 .../BaseWithZoneToIteratorOfListPage.java       |   2 +-
 .../internal/ParseGlobalOperations.java         |   2 +-
 .../internal/ParseRegionOperations.java         |  23 +-
 .../functions/internal/ParseZoneOperations.java |  23 +-
 .../GlobalOperationDonePredicate.java           |  54 ----
 .../predicates/InstancePredicates.java          |  33 ---
 .../predicates/NetworkFirewallPredicates.java   | 125 --------
 .../RegionOperationDonePredicate.java           |  62 ----
 .../predicates/ZoneOperationDonePredicate.java  |  65 ----
 .../GoogleComputeEngineServiceExpectTest.java   |  32 +-
 .../functions/CreateNetworkIfNeededTest.java    |  53 ++--
 .../functions/FindNetworkOrCreateTest.java      |  60 ++--
 .../GoogleComputeEngineImageToImageTest.java    |   2 +-
 .../functions/NetworkToSecurityGroupTest.java   |   8 +-
 .../OrphanedGroupsFromDeadNodesTest.java        |  22 +-
 .../features/AddressApiLiveTest.java            |   8 +-
 .../features/DiskApiLiveTest.java               |   9 +-
 .../features/FirewallApiLiveTest.java           |  29 +-
 .../features/ForwardingRuleApiLiveTest.java     |  19 +-
 .../features/GlobalOperationApiExpectTest.java  | 157 ----------
 .../features/GlobalOperationApiLiveTest.java    |  64 ----
 .../features/HttpHealthCheckApiLiveTest.java    |  10 +-
 .../features/ImageApiLiveTest.java              |   9 +-
 .../features/InstanceApiLiveTest.java           |  54 ++--
 .../features/NetworkApiLiveTest.java            |   5 +-
 .../features/OperationApiExpectTest.java        | 294 +++++++++++++++++++
 .../features/OperationApiLiveTest.java          |  98 +++++++
 .../features/ProjectApiLiveTest.java            |  12 +-
 .../features/RegionOperationApiExpectTest.java  | 168 -----------
 .../features/RegionOperationApiLiveTest.java    |  64 ----
 .../features/RouteApiLiveTest.java              |  15 +-
 .../features/SnapshotApiLiveTest.java           |   9 +-
 .../features/TargetPoolApiExpectTest.java       |  15 +-
 .../features/TargetPoolApiLiveTest.java         |  45 ++-
 .../features/ZoneOperationApiExpectTest.java    | 170 -----------
 .../features/ZoneOperationApiLiveTest.java      |  64 ----
 .../BaseGoogleComputeEngineApiLiveTest.java     |  62 ++--
 .../parse/ParseOperationTest.java               |   2 +-
 .../parse/ParseZoneOperationTest.java           |   2 +-
 .../NetworkFirewallPredicatesTest.java          |  10 +-
 .../src/test/resources/operation.json           |   2 +-
 .../src/test/resources/operation_error.json     |   4 +-
 .../src/test/resources/operation_list.json      |   2 +-
 .../src/test/resources/zone_operation.json      |   2 +-
 .../test/resources/zone_operation_error.json    |   4 +-
 .../src/test/resources/zone_operation_list.json |   2 +-
 72 files changed, 1255 insertions(+), 1870 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/pom.xml
----------------------------------------------------------------------
diff --git a/google-compute-engine/pom.xml b/google-compute-engine/pom.xml
index ac45197..a5913a2 100644
--- a/google-compute-engine/pom.xml
+++ b/google-compute-engine/pom.xml
@@ -125,6 +125,7 @@
                                     <goal>test</goal>
                                 </goals>
                                 <configuration>
+                                    <threadCount>1</threadCount>
                                     <systemPropertyVariables>
                                         <test.google-compute-engine.identity>${test.google-compute-engine.identity}
                                         </test.google-compute-engine.identity>

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
index 095f8c8..807e84a 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/GoogleComputeEngineApi.java
@@ -26,32 +26,20 @@ import org.jclouds.googlecomputeengine.features.DiskApi;
 import org.jclouds.googlecomputeengine.features.DiskTypeApi;
 import org.jclouds.googlecomputeengine.features.FirewallApi;
 import org.jclouds.googlecomputeengine.features.ForwardingRuleApi;
-import org.jclouds.googlecomputeengine.features.GlobalOperationApi;
 import org.jclouds.googlecomputeengine.features.HttpHealthCheckApi;
 import org.jclouds.googlecomputeengine.features.ImageApi;
 import org.jclouds.googlecomputeengine.features.InstanceApi;
 import org.jclouds.googlecomputeengine.features.MachineTypeApi;
 import org.jclouds.googlecomputeengine.features.NetworkApi;
+import org.jclouds.googlecomputeengine.features.OperationApi;
 import org.jclouds.googlecomputeengine.features.ProjectApi;
 import org.jclouds.googlecomputeengine.features.RegionApi;
-import org.jclouds.googlecomputeengine.features.RegionOperationApi;
 import org.jclouds.googlecomputeengine.features.RouteApi;
 import org.jclouds.googlecomputeengine.features.SnapshotApi;
 import org.jclouds.googlecomputeengine.features.TargetPoolApi;
 import org.jclouds.googlecomputeengine.features.ZoneApi;
-import org.jclouds.googlecomputeengine.features.ZoneOperationApi;
 import org.jclouds.rest.annotations.Delegate;
 
-import com.google.common.annotations.Beta;
-
-
-/**
- * Provides access to GoogleCompute.
- * <p/>
- *
- * @see <a href="https://developers.google.com/compute/docs/reference/v1">api doc</a>
- */
-@Beta
 public interface GoogleComputeEngineApi extends Closeable {
 
    /**
@@ -104,15 +92,6 @@ public interface GoogleComputeEngineApi extends Closeable {
    ForwardingRuleApi getForwardingRuleApi(@PathParam("project") String projectName, @PathParam("region") String region);
 
    /**
-    * Provides access to Global Operation features
-    *
-    * @param projectName the name of the project
-    */
-   @Delegate
-   @Path("/projects/{project}/global")
-   GlobalOperationApi getGlobalOperationApi(@PathParam("project") String projectName);
-
-   /**
     * Provides access to HttpHealthCheck features
     *
     * @param projectName the name of the project
@@ -160,6 +139,14 @@ public interface GoogleComputeEngineApi extends Closeable {
    NetworkApi getNetworkApi(@PathParam("project") String projectName);
 
    /**
+    * Provides access to Operation features
+    *
+    * @param projectName the name of the project
+    */
+   @Delegate
+   OperationApi getOperationApi(@PathParam("project") String projectName);
+
+   /**
     * Provides access to Project features
     */
    @Delegate
@@ -175,16 +162,6 @@ public interface GoogleComputeEngineApi extends Closeable {
    RegionApi getRegionApi(@PathParam("project") String projectName);
 
    /**
-    * Provides access to Region Operation features
-    *
-    * @param project the name of the project
-    * @param region     the name of the region scoping this request.
-    */
-   @Delegate
-   @Path("/projects/{project}/regions/{region}")
-   RegionOperationApi getRegionOperationApi(@PathParam("project") String project, @PathParam("region") String region);
-
-   /**
     * Provides access to Route features
     *
     * @param projectName the name of the project
@@ -220,14 +197,4 @@ public interface GoogleComputeEngineApi extends Closeable {
    @Delegate
    @Path("/projects/{project}")
    ZoneApi getZoneApi(@PathParam("project") String projectName);
-
-   /**
-    * Provides access to Zone Operation features
-    *
-    * @param projectName the name of the project
-    * @param zone        the name of the zone scoping this request.
-    */
-   @Delegate
-   @Path("/projects/{project}/zones/{zone}")
-   ZoneOperationApi getZoneOperationApi(@PathParam("project") String projectName, @PathParam("zone") String zone);
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
index 34b8a87..9abd6e7 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineService.java
@@ -16,15 +16,10 @@
  */
 package org.jclouds.googlecomputeengine.compute;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
 import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
 import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
 import static org.jclouds.googlecomputeengine.internal.ListPages.concat;
-import static org.jclouds.util.Predicates2.retry;
 
 import java.util.Map;
 import java.util.Set;
@@ -82,9 +77,7 @@ public final class GoogleComputeEngineService extends BaseComputeService {
    private final GroupNamingConvention.Factory namingConvention;
    private final GoogleComputeEngineApi api;
    private final Supplier<String> project;
-   private final Predicate<AtomicReference<Operation>> operationDonePredicate;
-   private final long operationCompleteCheckInterval;
-   private final long operationCompleteCheckTimeout;
+   private final Predicate<AtomicReference<Operation>> operationDone;
 
    @Inject GoogleComputeEngineService(ComputeServiceContext context,
                                         Map<String, Credentials> credentialStore,
@@ -119,24 +112,17 @@ public final class GoogleComputeEngineService extends BaseComputeService {
                                         GroupNamingConvention.Factory namingConvention,
                                         GoogleComputeEngineApi api,
                                         @UserProject Supplier<String> project,
-                                        @Named("global") Predicate<AtomicReference<Operation>> operationDonePredicate,
-                                        @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval,
-                                        @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) {
-
+                                        Predicate<AtomicReference<Operation>> operationDone) {
       super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getImageStrategy,
               getNodeMetadataStrategy, runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy,
               resumeNodeStrategy, suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning,
               nodeTerminated, nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory,
               persistNodeCredentials, timeouts, userExecutor, imageExtension, securityGroupExtension);
-      this.findOrphanedGroups = checkNotNull(findOrphanedGroups, "find orphaned groups function");
-      this.namingConvention = checkNotNull(namingConvention, "naming convention factory");
-      this.api = checkNotNull(api, "google compute api");
-      this.project = checkNotNull(project, "user project name");
-      this.operationDonePredicate = checkNotNull(operationDonePredicate, "operation completed predicate");
-      this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval,
-              "operation completed check interval");
-      this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout,
-              "operation completed check timeout");
+      this.findOrphanedGroups = findOrphanedGroups;
+      this.namingConvention = namingConvention;
+      this.api = api;
+      this.project = project;
+      this.operationDone = operationDone;
    }
 
    @Override
@@ -157,8 +143,7 @@ public final class GoogleComputeEngineService extends BaseComputeService {
             continue;
          }
          AtomicReference<Operation> operation = Atomics.newReference(firewallApi.delete(firewall.name()));
-         retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval,
-                 MILLISECONDS).apply(operation);
+         operationDone.apply(operation);
 
          if (operation.get().httpErrorStatusCode() != null) {
             logger.warn("delete orphaned firewall %s failed. Http Error Code: %d HttpError: %s",
@@ -170,8 +155,7 @@ public final class GoogleComputeEngineService extends BaseComputeService {
       AtomicReference<Operation> operation = Atomics
             .newReference(api.getNetworkApi(project.get()).delete(resourceName));
 
-      retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
-            .apply(operation);
+      operationDone.apply(operation);
 
       if (operation.get().httpErrorStatusCode() != null) {
          logger.warn("delete orphaned network failed. Http Error Code: " + operation.get().httpErrorStatusCode() +

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
index 4299eab..586f137 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/GoogleComputeEngineServiceAdapter.java
@@ -23,24 +23,18 @@ import static com.google.common.collect.Iterables.filter;
 import static com.google.common.collect.Iterables.transform;
 import static com.google.common.collect.Iterables.tryFind;
 import static com.google.common.collect.Lists.newArrayList;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_BOOT_DISK_SUFFIX;
 import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_DELETE_BOOT_DISK_METADATA_KEY;
 import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_METADATA_KEY;
 import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.GCE_IMAGE_PROJECTS;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
 import static org.jclouds.googlecomputeengine.domain.Instance.NetworkInterface.AccessConfig.Type;
 import static org.jclouds.googlecomputeengine.internal.ListPages.concat;
-import static org.jclouds.googlecomputeengine.predicates.InstancePredicates.isBootDisk;
-import static org.jclouds.util.Predicates2.retry;
 
 import java.net.URI;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Set;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.inject.Inject;
@@ -66,7 +60,9 @@ import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk;
 import org.jclouds.googlecomputeengine.domain.Instance.AttachedDisk.Mode;
 import org.jclouds.googlecomputeengine.domain.ListPage;
 import org.jclouds.googlecomputeengine.domain.MachineType;
+import org.jclouds.googlecomputeengine.domain.Metadata;
 import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.googlecomputeengine.domain.Tags;
 import org.jclouds.googlecomputeengine.domain.templates.InstanceTemplate;
 import org.jclouds.googlecomputeengine.domain.templates.InstanceTemplate.PersistentDisk;
 import org.jclouds.googlecomputeengine.features.DiskApi;
@@ -94,9 +90,8 @@ public final class GoogleComputeEngineServiceAdapter
    private final Supplier<String> userProject;
    private final Supplier<Set<String>> zoneIds;
    private final Function<TemplateOptions, ImmutableMap.Builder<String, String>> metatadaFromTemplateOptions;
-   private final Predicate<AtomicReference<Operation>> retryOperationDonePredicate;
-   private final long operationCompleteCheckInterval;
-   private final long operationCompleteCheckTimeout;
+   private final Predicate<AtomicReference<Operation>> operationDone;
+   private final Predicate<AtomicReference<Instance>> instanceVisible;
    private final FirewallTagNamingConvention.Factory firewallTagNamingConvention;
    private final List<String> imageProjects;
 
@@ -104,19 +99,16 @@ public final class GoogleComputeEngineServiceAdapter
                                             @UserProject Supplier<String> userProject,
                                             Function<TemplateOptions,
                                                     ImmutableMap.Builder<String, String>> metatadaFromTemplateOptions,
-                                            @Named("zone") Predicate<AtomicReference<Operation>> operationDonePredicate,
-                                            @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval,
-                                            @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout,
+                                            Predicate<AtomicReference<Operation>> operationDone,
+                                            Predicate<AtomicReference<Instance>> instanceVisible,
                                             @Zone Supplier<Set<String>> zoneIds,
                                             FirewallTagNamingConvention.Factory firewallTagNamingConvention,
                                             @Named(GCE_IMAGE_PROJECTS) String imageProjects) {
       this.api = api;
       this.userProject = userProject;
       this.metatadaFromTemplateOptions = metatadaFromTemplateOptions;
-      this.operationCompleteCheckInterval = operationCompleteCheckInterval;
-      this.operationCompleteCheckTimeout = operationCompleteCheckTimeout;
-      this.retryOperationDonePredicate = retry(operationDonePredicate, operationCompleteCheckTimeout,
-                                               operationCompleteCheckInterval, TimeUnit.MILLISECONDS);
+      this.operationDone = operationDone;
+      this.instanceVisible = instanceVisible;
       this.zoneIds = zoneIds;
       this.firewallTagNamingConvention = firewallTagNamingConvention;
       this.imageProjects = Splitter.on(',').splitToList(imageProjects);
@@ -174,34 +166,39 @@ public final class GoogleComputeEngineServiceAdapter
       instanceTemplate.serviceAccounts(options.getServiceAccounts());
 
       String zone = template.getLocation().getId();
-      final InstanceApi instanceApi = api.getInstanceApi(userProject.get(), zone);
+      InstanceApi instanceApi = api.getInstanceApi(userProject.get(), zone);
       Operation operation = instanceApi.create(name, instanceTemplate);
 
       if (options.shouldBlockUntilRunning()) {
          waitOperationDone(operation);
       }
 
-      // some times the newly created instances are not immediately returned
-      AtomicReference<Instance> instance = Atomics.newReference();
-
-      retry(new Predicate<AtomicReference<Instance>>() {
-         @Override public boolean apply(AtomicReference<Instance> input) {
-            input.set(instanceApi.get(name));
-            return input.get() != null;
-         }
-      }, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS).apply(instance);
+      // Some times the newly created instances are not immediately visible to the api.
+      // Make sure that we have a stub object in case that happens.
+      AtomicReference<Instance> instance = Atomics.newReference(Instance.create( //
+            "0000000000000000000", // id can't be null, but isn't available until provisioning is done.
+            operation.targetLink(), // selfLink
+            instanceTemplate.name(), // name
+            instanceTemplate.description(), // description
+            Tags.create(null, null), // tags
+            instanceTemplate.machineType(), // machineType
+            Instance.Status.PROVISIONING, // status
+            null, // statusMessage
+            operation.zone(), // zone
+            null, // networkInterfaces
+            null, // disks
+            Metadata.create(null, null), // metadata
+            instanceTemplate.serviceAccounts() // serviceAccounts
+      ));
+
+      instanceVisible.apply(instance);
 
       if (!options.getTags().isEmpty()) {
          Operation tagsOperation = instanceApi.setTags(name, options.getTags(), instance.get().tags().fingerprint());
 
          waitOperationDone(tagsOperation);
 
-         retry(new Predicate<AtomicReference<Instance>>() {
-            @Override public boolean apply(AtomicReference<Instance> input) {
-               input.set(instanceApi.get(name));
-               return input.get() != null;
-            }
-         }, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS).apply(instance);
+         instanceVisible.apply(instance);
       }
 
       // Add tags for security groups
@@ -397,7 +394,7 @@ public final class GoogleComputeEngineServiceAdapter
       AtomicReference<Operation> operationRef = Atomics.newReference(operation);
 
       // wait for the operation to complete
-      if (!retryOperationDonePredicate.apply(operationRef)) {
+      if (!operationDone.apply(operationRef)) {
          throw new UncheckedTimeoutException("operation did not reach DONE state" + operationRef.get());
       }
 
@@ -408,4 +405,12 @@ public final class GoogleComputeEngineServiceAdapter
                      " HttpError: " + operationRef.get().httpErrorMessage());
       }
    }
+
+   private static Predicate<PersistentDisk> isBootDisk() {
+      return new Predicate<PersistentDisk>() {
+         @Override public boolean apply(PersistentDisk input) {
+            return input.boot();
+         }
+      };
+   }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
index 76dabd7..d7317b2 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/config/GoogleComputeEngineServiceContextModule.java
@@ -17,12 +17,18 @@
 package org.jclouds.googlecomputeengine.compute.config;
 
 import static com.google.common.base.Suppliers.memoizeWithExpiration;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
+import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
+import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
+import static org.jclouds.rest.config.BinderUtils.bindHttpApi;
+import static org.jclouds.util.Predicates2.retry;
 
 import java.net.URI;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -55,8 +61,11 @@ import org.jclouds.googlecomputeengine.compute.functions.InstanceInZoneToNodeMet
 import org.jclouds.googlecomputeengine.compute.functions.MachineTypeInZoneToHardware;
 import org.jclouds.googlecomputeengine.compute.functions.NetworkToSecurityGroup;
 import org.jclouds.googlecomputeengine.compute.functions.OrphanedGroupsFromDeadNodes;
+import org.jclouds.googlecomputeengine.compute.functions.ResourceFunctions;
 import org.jclouds.googlecomputeengine.compute.options.GoogleComputeEngineTemplateOptions;
 import org.jclouds.googlecomputeengine.compute.predicates.AllNodesInGroupTerminated;
+import org.jclouds.googlecomputeengine.compute.predicates.AtomicInstanceVisible;
+import org.jclouds.googlecomputeengine.compute.predicates.AtomicOperationDone;
 import org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet;
 import org.jclouds.googlecomputeengine.compute.strategy.PopulateDefaultLoginCredentialsForImageStrategy;
 import org.jclouds.googlecomputeengine.compute.strategy.UseNodeCredentialsButOverrideFromTemplate;
@@ -64,6 +73,7 @@ import org.jclouds.googlecomputeengine.domain.Firewall;
 import org.jclouds.googlecomputeengine.domain.Image;
 import org.jclouds.googlecomputeengine.domain.Instance;
 import org.jclouds.googlecomputeengine.domain.Network;
+import org.jclouds.googlecomputeengine.domain.Operation;
 import org.jclouds.net.domain.IpPermission;
 
 import com.google.common.base.Function;
@@ -137,6 +147,19 @@ public final class GoogleComputeEngineServiceContextModule
 
       bind(PrioritizeCredentialsFromTemplate.class).to(UseNodeCredentialsButOverrideFromTemplate.class);
       bind(FirewallTagNamingConvention.Factory.class).in(Scopes.SINGLETON);
+
+      bindHttpApi(binder(), ResourceFunctions.class);
+   }
+
+   // TODO: these timeouts need thinking through.
+   @Provides Predicate<AtomicReference<Operation>> operationDone(AtomicOperationDone input,
+         @Named(OPERATION_COMPLETE_TIMEOUT) long timeout, @Named(OPERATION_COMPLETE_INTERVAL) long interval) {
+      return retry(input, timeout, interval, MILLISECONDS);
+   }
+
+   @Provides Predicate<AtomicReference<Instance>> instanceVisible(AtomicInstanceVisible input,
+         @Named(OPERATION_COMPLETE_TIMEOUT) long timeout, @Named(OPERATION_COMPLETE_INTERVAL) long interval) {
+      return retry(input, timeout, interval, MILLISECONDS);
    }
 
    @Provides @Singleton @Memoized Supplier<Map<URI, org.jclouds.compute.domain.Image>> imageByUri(

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
index 28ee3eb..d92b304 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/extensions/GoogleComputeEngineSecurityGroupExtension.java
@@ -21,11 +21,11 @@ import static com.google.common.base.Preconditions.checkState;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
 import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
+import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.equalsIpPermission;
+import static org.jclouds.googlecomputeengine.compute.predicates.NetworkFirewallPredicates.providesIpPermission;
 import static org.jclouds.googlecomputeengine.compute.strategy.CreateNodesWithGroupEncodedIntoNameThenAddToSet.DEFAULT_INTERNAL_NETWORK_RANGE;
 import static org.jclouds.googlecomputeengine.internal.ListPages.concat;
 import static org.jclouds.googlecomputeengine.options.ListOptions.Builder.filter;
-import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.equalsIpPermission;
-import static org.jclouds.googlecomputeengine.predicates.NetworkFirewallPredicates.providesIpPermission;
 import static org.jclouds.util.Predicates2.retry;
 
 import java.util.Collection;
@@ -66,38 +66,31 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.Atomics;
 
-/**
- * An extension to compute service to allow for the manipulation of {@link org.jclouds.compute.domain.SecurityGroup}s.
- * Implementation
- * is optional by providers.
- */
-public class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupExtension {
+public final class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupExtension {
 
    private final Supplier<String> userProject;
    private final GroupNamingConvention.Factory namingConvention;
    private final LoadingCache<NetworkAndAddressRange, Network> networkCreator;
    private final Function<Network, SecurityGroup> groupConverter;
    private final GoogleComputeEngineApi api;
-   private final Predicate<AtomicReference<Operation>> operationDonePredicate;
+   private final Predicate<AtomicReference<Operation>> operationDone;
    private final long operationCompleteCheckInterval;
    private final long operationCompleteCheckTimeout;
 
    @Inject GoogleComputeEngineSecurityGroupExtension(GoogleComputeEngineApi api,
          @UserProject Supplier<String> userProject, GroupNamingConvention.Factory namingConvention,
          LoadingCache<NetworkAndAddressRange, Network> networkCreator, Function<Network, SecurityGroup> groupConverter,
-         @Named("global") Predicate<AtomicReference<Operation>> operationDonePredicate,
+         Predicate<AtomicReference<Operation>> operationDone,
          @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval,
          @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) {
-      this.api = checkNotNull(api, "api");
-      this.userProject = checkNotNull(userProject, "userProject");
-      this.namingConvention = checkNotNull(namingConvention, "namingConvention");
-      this.networkCreator = checkNotNull(networkCreator, "networkCreator");
-      this.groupConverter = checkNotNull(groupConverter, "groupConverter");
-      this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval,
-            "operation completed check interval");
-      this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout,
-            "operation completed check timeout");
-      this.operationDonePredicate = checkNotNull(operationDonePredicate, "operationDonePredicate");
+      this.api = api;
+      this.userProject = userProject;
+      this.namingConvention = namingConvention;
+      this.networkCreator = networkCreator;
+      this.groupConverter = groupConverter;
+      this.operationCompleteCheckInterval = operationCompleteCheckInterval;
+      this.operationCompleteCheckTimeout = operationCompleteCheckTimeout;
+      this.operationDone = operationDone;
    }
 
    @Override
@@ -177,7 +170,7 @@ public class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupE
          AtomicReference<Operation> operation = Atomics
                .newReference(api.getFirewallApi(userProject.get()).delete(fw.name()));
 
-         retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
+         retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
                .apply(operation);
 
          checkState(operation.get().httpErrorStatusCode() == null,
@@ -186,7 +179,7 @@ public class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupE
 
       AtomicReference<Operation> operation = Atomics.newReference(api.getNetworkApi(userProject.get()).delete(id));
 
-      retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
+      retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
             .apply(operation);
 
       checkState(operation.get().httpErrorStatusCode() == null,
@@ -233,7 +226,7 @@ public class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupE
       AtomicReference<Operation> operation = Atomics.newReference(
             api.getFirewallApi(userProject.get()).createInNetwork(uniqueFwName, group.getUri(), fwOptions));
 
-      retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
+      retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
             .apply(operation);
 
       checkState(operation.get().httpErrorStatusCode() == null,
@@ -274,7 +267,7 @@ public class GoogleComputeEngineSecurityGroupExtension implements SecurityGroupE
             AtomicReference<Operation> operation = Atomics
                   .newReference(api.getFirewallApi(userProject.get()).delete(fw.name()));
 
-            retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
+            retry(operationDone, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
                   .apply(operation);
 
             checkState(operation.get().httpErrorStatusCode() == null,

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
index 4b4b113..338b731 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/CreateNetworkIfNeeded.java
@@ -18,15 +18,10 @@ package org.jclouds.googlecomputeengine.compute.functions;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
-import static org.jclouds.util.Predicates2.retry;
 
 import java.util.concurrent.atomic.AtomicReference;
 
 import javax.inject.Inject;
-import javax.inject.Named;
 
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.NetworkAndAddressRange;
@@ -39,24 +34,16 @@ import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.util.concurrent.Atomics;
 
-public class CreateNetworkIfNeeded implements Function<NetworkAndAddressRange, Network> {
+public final class CreateNetworkIfNeeded implements Function<NetworkAndAddressRange, Network> {
    private final GoogleComputeEngineApi api;
    private final Supplier<String> userProject;
-   private final Predicate<AtomicReference<Operation>> operationDonePredicate;
-   private final long operationCompleteCheckInterval;
-   private final long operationCompleteCheckTimeout;
+   private final Predicate<AtomicReference<Operation>> operationDone;
 
    @Inject CreateNetworkIfNeeded(GoogleComputeEngineApi api, @UserProject Supplier<String> userProject,
-         @Named("global") Predicate<AtomicReference<Operation>> operationDonePredicate,
-         @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval,
-         @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout) {
-      this.api = checkNotNull(api, "api");
-      this.userProject = checkNotNull(userProject, "userProject");
-      this.operationCompleteCheckInterval = checkNotNull(operationCompleteCheckInterval,
-            "operation completed check interval");
-      this.operationCompleteCheckTimeout = checkNotNull(operationCompleteCheckTimeout,
-            "operation completed check timeout");
-      this.operationDonePredicate = checkNotNull(operationDonePredicate, "operationDonePredicate");
+         Predicate<AtomicReference<Operation>> operationDone) {
+      this.api = api;
+      this.userProject = userProject;
+      this.operationDone = operationDone;
    }
 
    @Override
@@ -71,16 +58,14 @@ public class CreateNetworkIfNeeded implements Function<NetworkAndAddressRange, N
       if (input.gateway() != null) {
          AtomicReference<Operation> operation = Atomics.newReference(api.getNetworkApi(userProject.get())
                .createInIPv4RangeWithGateway(input.name(), input.rangeIPv4(), input.gateway()));
-         retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
-               .apply(operation);
+         operationDone.apply(operation);
 
          checkState(operation.get().httpErrorStatusCode() == null,
                "Could not insert network, operation failed" + operation);
       } else {
          AtomicReference<Operation> operation = Atomics
                .newReference(api.getNetworkApi(userProject.get()).createInIPv4Range(input.name(), input.rangeIPv4()));
-         retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval, MILLISECONDS)
-               .apply(operation);
+         operationDone.apply(operation);
 
          checkState(operation.get().httpErrorStatusCode() == null,
                "Could not insert network, operation failed" + operation);

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java
index 51e331b..517221b 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/FirewallTagNamingConvention.java
@@ -25,14 +25,13 @@ import com.google.common.base.Predicate;
 /**
  * The convention for naming instance tags that firewall rules recognise.
  */
-public class FirewallTagNamingConvention {
+public final class FirewallTagNamingConvention {
 
-   public static class Factory {
+   public static final class Factory {
 
       private final GroupNamingConvention.Factory namingConvention;
 
-      @Inject
-      public Factory(GroupNamingConvention.Factory namingConvention) {
+      @Inject Factory(GroupNamingConvention.Factory namingConvention) {
          this.namingConvention = namingConvention;
       }
 
@@ -59,5 +58,4 @@ public class FirewallTagNamingConvention {
          }
       };
    }
-
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ResourceFunctions.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ResourceFunctions.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ResourceFunctions.java
new file mode 100644
index 0000000..6b16725
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/functions/ResourceFunctions.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.googlecomputeengine.compute.functions;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
+
+import java.net.URI;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+
+import org.jclouds.googlecomputeengine.domain.Instance;
+import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.oauth.v2.config.OAuthScopes;
+import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
+import org.jclouds.rest.annotations.EndpointParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.SkipEncoding;
+
+@SkipEncoding({'/', '='})
+@RequestFilters(OAuthAuthenticationFilter.class)
+@Consumes(APPLICATION_JSON)
+public interface ResourceFunctions {
+
+   /** Returns an instance by self-link or null if not found. */
+   @Named("Instances:get")
+   @GET
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @Fallback(NullOnNotFoundOr404.class) @Nullable Instance instance(@EndpointParam URI selfLink);
+
+   /** Returns an operation by self-link or null if not found. */
+   @Named("Operations:get")
+   @GET
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @Fallback(NullOnNotFoundOr404.class) @Nullable Operation operation(@EndpointParam URI selfLink);
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java
index 38066ba..7897907 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AllNodesInGroupTerminated.java
@@ -16,7 +16,6 @@
  */
 package org.jclouds.googlecomputeengine.compute.predicates;
 
-import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.all;
 import static com.google.common.collect.Sets.filter;
 import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
@@ -24,25 +23,21 @@ import static org.jclouds.compute.predicates.NodePredicates.all;
 import static org.jclouds.compute.predicates.NodePredicates.inGroup;
 
 import javax.inject.Inject;
-import javax.inject.Singleton;
 
 import org.jclouds.compute.ComputeService;
 
 import com.google.common.base.Predicate;
 
-@Singleton
-public class AllNodesInGroupTerminated implements Predicate<String> {
+public final class AllNodesInGroupTerminated implements Predicate<String> {
 
    private final ComputeService computeService;
 
-   @Inject
-   public AllNodesInGroupTerminated(ComputeService computeService) {
-      this.computeService = checkNotNull(computeService, "compute service");
+   @Inject AllNodesInGroupTerminated(ComputeService computeService) {
+      this.computeService = computeService;
    }
 
 
-   @Override
-   public boolean apply(String groupName) {
+   @Override public boolean apply(String groupName) {
       return all(filter(computeService.listNodesDetailsMatching(all()), inGroup(groupName)), TERMINATED);
    }
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicInstanceVisible.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicInstanceVisible.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicInstanceVisible.java
new file mode 100644
index 0000000..09d4486
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicInstanceVisible.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.googlecomputeengine.compute.predicates;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.inject.Inject;
+
+import org.jclouds.googlecomputeengine.compute.functions.ResourceFunctions;
+import org.jclouds.googlecomputeengine.domain.Instance;
+
+import com.google.common.base.Predicate;
+
+public final class AtomicInstanceVisible implements Predicate<AtomicReference<Instance>> {
+
+   private final ResourceFunctions resources;
+
+   @Inject AtomicInstanceVisible(ResourceFunctions resources) {
+      this.resources = resources;
+   }
+
+   @Override public boolean apply(AtomicReference<Instance> input) {
+      Instance response = resources.instance(input.get().selfLink());
+      if (response == null) {
+         return false;
+      }
+      input.set(response);
+      return true;
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicOperationDone.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicOperationDone.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicOperationDone.java
new file mode 100644
index 0000000..afe0dd0
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/AtomicOperationDone.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.googlecomputeengine.compute.predicates;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.inject.Inject;
+
+import org.jclouds.googlecomputeengine.compute.functions.ResourceFunctions;
+import org.jclouds.googlecomputeengine.domain.Operation;
+
+import com.google.common.base.Predicate;
+
+public final class AtomicOperationDone implements Predicate<AtomicReference<Operation>> {
+
+   private final ResourceFunctions resources;
+
+   @Inject AtomicOperationDone(ResourceFunctions resources) {
+      this.resources = resources;
+   }
+
+   @Override public boolean apply(AtomicReference<Operation> input) {
+      checkNotNull(input.get(), "operation");
+      Operation current = resources.operation(input.get().selfLink());
+      input.set(current);
+      checkState(current.errors().isEmpty(), "Task ended in error %s", current); // ISE will break the loop.
+      switch (current.status()) {
+         case DONE:
+            return true;
+         case PENDING:
+         case RUNNING:
+         default:
+            return false;
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/NetworkFirewallPredicates.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/NetworkFirewallPredicates.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/NetworkFirewallPredicates.java
new file mode 100644
index 0000000..02b189a
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/predicates/NetworkFirewallPredicates.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.googlecomputeengine.compute.predicates;
+
+import static com.google.common.collect.Sets.intersection;
+
+import java.util.List;
+
+import org.jclouds.googlecomputeengine.domain.Firewall;
+import org.jclouds.googlecomputeengine.domain.Firewall.Rule;
+import org.jclouds.net.domain.IpPermission;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+
+public final class NetworkFirewallPredicates {
+
+   public static Predicate<Firewall> hasPortRange(final String protocol, final int fromPort, final int toPort) {
+      return new Predicate<Firewall>() {
+         @Override public boolean apply(Firewall fw) {
+            for (Rule rule : fw.allowed()) {
+               if (!rule.ipProtocol().equals(protocol)) {
+                  continue;
+               }
+               if (rule.ports() == null || rule.ports().isEmpty()) {
+                  return true;
+               }
+               for (String range : rule.ports()) {
+                  if (range.indexOf('-') != -1) {
+                     if (inRange(range, fromPort, toPort)) {
+                        return true;
+                     }
+                  }
+               }
+            }
+            return false;
+         }
+      };
+   }
+
+   private static boolean inRange(String range, int fromPort, int toPort) {
+      List<String> ports = Splitter.on('-').splitToList(range);
+      return fromPort >= Integer.valueOf(ports.get(0)) && toPort <= Integer.valueOf(ports.get(1));
+   }
+
+   public static Predicate<Firewall> hasSourceTag(final String sourceTag) {
+      return new Predicate<Firewall>() {
+         @Override public boolean apply(Firewall input) {
+            return input.sourceTags().contains(sourceTag);
+         }
+      };
+   }
+
+   public static Predicate<Firewall> hasSourceRange(final String sourceRange) {
+      return new Predicate<Firewall>() {
+         @Override  public boolean apply(Firewall input) {
+            return input.sourceRanges().contains(sourceRange);
+         }
+      };
+   }
+
+   public static Predicate<Firewall> equalsIpPermission(final IpPermission permission) {
+      return new Predicate<Firewall>() {
+         @Override public boolean apply(Firewall input) {
+            return Iterables.elementsEqual(permission.getGroupIds(), input.sourceTags())
+                      && Iterables.elementsEqual(permission.getCidrBlocks(), input.sourceRanges())
+                      && (input.allowed().size() == 1
+                             && ruleEqualsIpPermission(permission).apply(Iterables.getOnlyElement(input.allowed())));
+         }
+      };
+   }
+
+   public static Predicate<Firewall> providesIpPermission(final IpPermission permission) {
+      return new Predicate<Firewall>() {
+         @Override  public boolean apply(Firewall input) {
+            boolean groupsMatchTags =
+                  (permission.getGroupIds().isEmpty() && input.sourceTags().isEmpty()) || !intersection(
+                        permission.getGroupIds(), ImmutableSet.copyOf(input.sourceTags())).isEmpty();
+            boolean cidrsMatchRanges =
+                  (permission.getCidrBlocks().isEmpty() && input.sourceRanges().isEmpty()) || !intersection(
+                        permission.getCidrBlocks(), ImmutableSet.copyOf(input.sourceRanges())).isEmpty();
+            boolean firewallHasPorts = hasPortRange(permission.getIpProtocol().value().toLowerCase(),
+                        permission.getFromPort(), permission.getToPort()).apply(input);
+            return groupsMatchTags && cidrsMatchRanges && firewallHasPorts;
+         }
+      };
+   }
+
+   private static Predicate<Firewall.Rule> ruleEqualsIpPermission(final IpPermission permission) {
+      return new Predicate<Rule>() {
+         @Override public boolean apply(Firewall.Rule input) {
+            if (!permission.getIpProtocol().value().toLowerCase().equals(input.ipProtocol())) {
+               return false;
+            }
+            if (input.ports() == null
+                  || input.ports().isEmpty() && permission.getFromPort() == 0 && permission.getToPort() == 0) {
+               return true;
+            } else if (input.ports().size() == 1) {
+               String port = Iterables.getOnlyElement(input.ports());
+               if (permission.getFromPort() == permission.getToPort()) {
+                  return port.equals(String.valueOf(permission.getFromPort()));
+               }
+               return port.equals(permission.getFromPort() + "-" + permission.getToPort());
+            }
+            return false;
+         }
+      };
+   }
+}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
index b2ba892..ee2c877 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/compute/strategy/CreateNodesWithGroupEncodedIntoNameThenAddToSet.java
@@ -18,10 +18,6 @@ package org.jclouds.googlecomputeengine.compute.strategy;
 
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.ImmutableList.of;
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_INTERVAL;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.OPERATION_COMPLETE_TIMEOUT;
-import static org.jclouds.util.Predicates2.retry;
 
 import java.util.List;
 import java.util.Map;
@@ -62,7 +58,7 @@ import com.google.common.util.concurrent.Atomics;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 
-public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
+public final class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
         org.jclouds.compute.strategy.impl.CreateNodesWithGroupEncodedIntoNameThenAddToSet {
 
    public static final String EXTERIOR_RANGE = "0.0.0.0/0";
@@ -71,9 +67,7 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
    private final GoogleComputeEngineApi api;
    private final Supplier<String> userProject;
    private final LoadingCache<NetworkAndAddressRange, Network> networkMap;
-   private final Predicate<AtomicReference<Operation>> operationDonePredicate;
-   private final long operationCompleteCheckInterval;
-   private final long operationCompleteCheckTimeout;
+   private final Predicate<AtomicReference<Operation>> operationDone;
    private final FirewallTagNamingConvention.Factory firewallTagNamingConvention;
 
    @Inject CreateNodesWithGroupEncodedIntoNameThenAddToSet(
@@ -86,18 +80,14 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
                    customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
            GoogleComputeEngineApi api,
            @UserProject Supplier<String> userProject,
-           @Named("global") Predicate<AtomicReference<Operation>> operationDonePredicate,
-           @Named(OPERATION_COMPLETE_INTERVAL) Long operationCompleteCheckInterval,
-           @Named(OPERATION_COMPLETE_TIMEOUT) Long operationCompleteCheckTimeout,
+           Predicate<AtomicReference<Operation>> operationDone,
            LoadingCache<NetworkAndAddressRange, Network> networkMap,
            FirewallTagNamingConvention.Factory firewallTagNamingConvention) {
       super(addNodeWithGroupStrategy, listNodesStrategy, namingConvention, userExecutor,
               customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
       this.api = api;
       this.userProject = userProject;
-      this.operationCompleteCheckInterval = operationCompleteCheckInterval;
-      this.operationCompleteCheckTimeout = operationCompleteCheckTimeout;
-      this.operationDonePredicate = operationDonePredicate;
+      this.operationDone = operationDone;
       this.networkMap = networkMap;
       this.firewallTagNamingConvention = firewallTagNamingConvention;
    }
@@ -171,11 +161,9 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet extends
       }
 
       for (AtomicReference<Operation> operation : operations) {
-         retry(operationDonePredicate, operationCompleteCheckTimeout, operationCompleteCheckInterval,
-                 MILLISECONDS).apply(operation);
-         checkState(operation.get().httpErrorStatusCode() == null,
-               "Could not insert firewall, operation failed" + operation);
+         operationDone.apply(operation);
+         checkState(operation.get().httpErrorStatusCode() == null, "Could not insert firewall, operation failed %s",
+               operation);
       }
    }
-
 }

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
index 1f95582..23fed76 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/config/GoogleComputeEngineHttpApiModule.java
@@ -17,7 +17,6 @@
 package org.jclouds.googlecomputeengine.config;
 
 import static com.google.common.base.Suppliers.compose;
-import static com.google.inject.name.Names.named;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
 
@@ -30,18 +29,12 @@ import javax.inject.Singleton;
 import org.jclouds.domain.Credentials;
 import org.jclouds.googlecomputeengine.GoogleComputeEngineApi;
 import org.jclouds.googlecomputeengine.compute.domain.SlashEncodedIds;
-import org.jclouds.googlecomputeengine.domain.Operation;
 import org.jclouds.googlecomputeengine.handlers.GoogleComputeEngineErrorHandler;
-import org.jclouds.googlecomputeengine.predicates.GlobalOperationDonePredicate;
-import org.jclouds.googlecomputeengine.predicates.RegionOperationDonePredicate;
-import org.jclouds.googlecomputeengine.predicates.ZoneOperationDonePredicate;
 import org.jclouds.http.HttpErrorHandler;
 import org.jclouds.http.Uris;
 import org.jclouds.http.annotation.ClientError;
 import org.jclouds.http.annotation.Redirection;
 import org.jclouds.http.annotation.ServerError;
-import org.jclouds.json.config.GsonModule.DateAdapter;
-import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
 import org.jclouds.location.Provider;
 import org.jclouds.rest.AuthorizationException;
 import org.jclouds.rest.ConfiguresHttpApi;
@@ -49,12 +42,10 @@ import org.jclouds.rest.config.HttpApiModule;
 import org.jclouds.rest.suppliers.MemoizedRetryOnTimeOutButNotOnAuthorizationExceptionSupplier;
 
 import com.google.common.base.Function;
-import com.google.common.base.Predicate;
 import com.google.common.base.Splitter;
 import com.google.common.base.Supplier;
 import com.google.common.collect.Iterables;
 import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
 
 @ConfiguresHttpApi
 public final class GoogleComputeEngineHttpApiModule extends HttpApiModule<GoogleComputeEngineApi> {
@@ -62,18 +53,6 @@ public final class GoogleComputeEngineHttpApiModule extends HttpApiModule<Google
    }
 
    @Override
-   protected void configure() {
-      bind(DateAdapter.class).to(Iso8601DateAdapter.class);
-      bind(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {
-      }).annotatedWith(named("global")).to(GlobalOperationDonePredicate.class);
-      bind(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {
-      }).annotatedWith(named("region")).to(RegionOperationDonePredicate.class);
-      bind(new TypeLiteral<Predicate<AtomicReference<Operation>>>() {
-      }).annotatedWith(named("zone")).to(ZoneOperationDonePredicate.class);
-      super.configure();
-   }
-
-   @Override
    protected void bindErrorHandlers() {
       bind(HttpErrorHandler.class).annotatedWith(Redirection.class).to(GoogleComputeEngineErrorHandler.class);
       bind(HttpErrorHandler.class).annotatedWith(ClientError.class).to(GoogleComputeEngineErrorHandler.class);

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Tags.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Tags.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Tags.java
index ec92c33..cc1c880 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Tags.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/domain/Tags.java
@@ -29,12 +29,12 @@ import com.google.auto.value.AutoValue;
 @AutoValue
 public abstract class Tags {
    /** The fingerprint for the items - needed for updating them. */
-   public abstract String fingerprint();
+   @Nullable public abstract String fingerprint();
 
    public abstract List<String> items();
 
    @SerializedNames({ "fingerprint", "items" })
-   public static Tags create(String fingerprint, @Nullable List<String> items) {
+   public static Tags create(String fingerprint, List<String> items) {
       return new AutoValue_Tags(fingerprint, copyOf(items));
    }
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java
index 71bd2bb..679811d 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/AddressApi.java
@@ -77,7 +77,7 @@ public interface AddressApi {
    @Named("Addresses:insert")
    @POST
    @Produces(APPLICATION_JSON)
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    @MapBinder(BindToJsonPayload.class)
    Operation create(@PayloadParam("name") String address);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java
index 883d647..a9d8818 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/FirewallApi.java
@@ -85,7 +85,7 @@ public interface FirewallApi {
    @Named("Firewalls:insert")
    @POST
    @Produces(APPLICATION_JSON)
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    @MapBinder(FirewallBinder.class)
    Operation createInNetwork(@PayloadParam("name") String name,
                              @PayloadParam("network") URI network,
@@ -103,7 +103,7 @@ public interface FirewallApi {
    @PUT
    @Produces(APPLICATION_JSON)
    @Path("/{firewall}")
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    Operation update(@PathParam("firewall") String firewall,
                     @BinderParam(BindToJsonPayload.class) FirewallOptions firewallOptions);
 
@@ -119,7 +119,7 @@ public interface FirewallApi {
    @PATCH
    @Produces(APPLICATION_JSON)
    @Path("/{firewall}")
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    Operation patch(@PathParam("firewall") String firewall,
                    @BinderParam(BindToJsonPayload.class) FirewallOptions firewallOptions);
 

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java
deleted file mode 100644
index 892a8d8..0000000
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/GlobalOperationApi.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.jclouds.googlecomputeengine.features;
-
-import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
-import static org.jclouds.Fallbacks.VoidOnNotFoundOr404;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
-import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
-
-import java.util.Iterator;
-
-import javax.inject.Named;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.QueryParam;
-
-import org.jclouds.Fallbacks.NullOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyIteratorOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyListPageOnNotFoundOr404;
-import org.jclouds.googlecomputeengine.domain.ListPage;
-import org.jclouds.googlecomputeengine.domain.Operation;
-import org.jclouds.googlecomputeengine.functions.internal.ParseGlobalOperations;
-import org.jclouds.googlecomputeengine.options.ListOptions;
-import org.jclouds.javax.annotation.Nullable;
-import org.jclouds.oauth.v2.config.OAuthScopes;
-import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
-import org.jclouds.rest.annotations.Fallback;
-import org.jclouds.rest.annotations.RequestFilters;
-import org.jclouds.rest.annotations.ResponseParser;
-import org.jclouds.rest.annotations.SkipEncoding;
-import org.jclouds.rest.annotations.Transform;
-
-@SkipEncoding({'/', '='})
-@RequestFilters(OAuthAuthenticationFilter.class)
-@Path("/operations")
-@Consumes(APPLICATION_JSON)
-public interface GlobalOperationApi {
-
-   /** Returns an operation by name or null if not found. */
-   @Named("GlobalOperations:get")
-   @GET
-   @Path("/{operation}")
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @Fallback(NullOnNotFoundOr404.class)
-   @Nullable
-   Operation get(@PathParam("operation") String operation);
-
-   /** Deletes an operation by name. */
-   @Named("GlobalOperations:delete")
-   @DELETE
-   @Path("/{operation}")
-   @OAuthScopes(COMPUTE_SCOPE)
-   @Fallback(VoidOnNotFoundOr404.class)
-   void delete(@PathParam("operation") String operation);
-
-   /**
-    * Retrieves the list of operation resources available to the specified project.
-    * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not
-    * been set.
-    *
-    * @param token       marks the beginning of the next list page
-    * @param listOptions listing options
-    * @return a page of the list
-    */
-   @Named("GlobalOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseGlobalOperations.class)
-   @Fallback(EmptyListPageOnNotFoundOr404.class)
-   ListPage<Operation> listPage(@Nullable @QueryParam("pageToken") String token, ListOptions listOptions);
-
-   /**
-    * @see #list(org.jclouds.googlecomputeengine.options.ListOptions)
-    */
-   @Named("GlobalOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseGlobalOperations.class)
-   @Transform(ParseGlobalOperations.ToIteratorOfListPage.class)
-   @Fallback(EmptyIteratorOnNotFoundOr404.class)
-   Iterator<ListPage<Operation>> list();
-
-   /**
-    * @see #list(org.jclouds.googlecomputeengine.options.ListOptions)
-    */
-   @Named("GlobalOperations:list")
-   @GET
-   @OAuthScopes(COMPUTE_READONLY_SCOPE)
-   @ResponseParser(ParseGlobalOperations.class)
-   @Transform(ParseGlobalOperations.ToIteratorOfListPage.class)
-   @Fallback(EmptyIteratorOnNotFoundOr404.class)
-   Iterator<ListPage<Operation>> list(ListOptions options);
-}

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
index 33ed393..41524ec 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/InstanceApi.java
@@ -86,7 +86,7 @@ public interface InstanceApi {
    @Named("Instances:insert")
    @POST
    @Produces(APPLICATION_JSON)
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    @MapBinder(InstanceBinder.class)
    Operation create(@PayloadParam("name") String instance, @PayloadParam("template") InstanceTemplate template);
 
@@ -150,7 +150,7 @@ public interface InstanceApi {
    @POST
    @Produces(APPLICATION_JSON)
    @Path("/{instance}/addAccessConfig")
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    Operation addAccessConfigToNic(@PathParam("instance") String instance,
                                   @BinderParam(BindToJsonPayload.class)
                                   AccessConfig accessConfig,

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
index 7b80233..ed917a2 100644
--- a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/NetworkApi.java
@@ -77,7 +77,7 @@ public interface NetworkApi {
    @Named("Networks:insert")
    @POST
    @Produces(APPLICATION_JSON)
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    @MapBinder(BindToJsonPayload.class)
    Operation createInIPv4Range(@PayloadParam("name") String networkName,
                                @PayloadParam("IPv4Range") String IPv4Range);
@@ -94,7 +94,7 @@ public interface NetworkApi {
    @Named("Networks:insert")
    @POST
    @Produces(APPLICATION_JSON)
-   @OAuthScopes({COMPUTE_SCOPE})
+   @OAuthScopes(COMPUTE_SCOPE)
    @MapBinder(BindToJsonPayload.class)
    Operation createInIPv4RangeWithGateway(@PayloadParam("name") String networkName,
                                           @PayloadParam("IPv4Range") String IPv4Range,

http://git-wip-us.apache.org/repos/asf/jclouds-labs-google/blob/8895953d/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/OperationApi.java
----------------------------------------------------------------------
diff --git a/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/OperationApi.java b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/OperationApi.java
new file mode 100644
index 0000000..49bbaf9
--- /dev/null
+++ b/google-compute-engine/src/main/java/org/jclouds/googlecomputeengine/features/OperationApi.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jclouds.googlecomputeengine.features;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.jclouds.Fallbacks.VoidOnNotFoundOr404;
+import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_READONLY_SCOPE;
+import static org.jclouds.googlecomputeengine.GoogleComputeEngineConstants.COMPUTE_SCOPE;
+
+import java.net.URI;
+import java.util.Iterator;
+
+import javax.inject.Named;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
+
+import org.jclouds.Fallbacks.NullOnNotFoundOr404;
+import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyIteratorOnNotFoundOr404;
+import org.jclouds.googlecomputeengine.GoogleComputeEngineFallbacks.EmptyListPageOnNotFoundOr404;
+import org.jclouds.googlecomputeengine.domain.ListPage;
+import org.jclouds.googlecomputeengine.domain.Operation;
+import org.jclouds.googlecomputeengine.functions.internal.ParseGlobalOperations;
+import org.jclouds.googlecomputeengine.functions.internal.ParseRegionOperations;
+import org.jclouds.googlecomputeengine.functions.internal.ParseZoneOperations;
+import org.jclouds.googlecomputeengine.options.ListOptions;
+import org.jclouds.javax.annotation.Nullable;
+import org.jclouds.oauth.v2.config.OAuthScopes;
+import org.jclouds.oauth.v2.filters.OAuthAuthenticationFilter;
+import org.jclouds.rest.annotations.EndpointParam;
+import org.jclouds.rest.annotations.Fallback;
+import org.jclouds.rest.annotations.RequestFilters;
+import org.jclouds.rest.annotations.ResponseParser;
+import org.jclouds.rest.annotations.SkipEncoding;
+import org.jclouds.rest.annotations.Transform;
+
+@SkipEncoding({'/', '='})
+@RequestFilters(OAuthAuthenticationFilter.class)
+@Consumes(APPLICATION_JSON)
+public interface OperationApi {
+
+   /** Returns an operation by self-link or null if not found. */
+   @Named("Operations:get")
+   @GET
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @Fallback(NullOnNotFoundOr404.class)
+   @Nullable
+   Operation get(@EndpointParam URI operation);
+
+   /** Deletes an operation by name. */
+   @Named("Operations:delete")
+   @DELETE
+   @OAuthScopes(COMPUTE_SCOPE)
+   @Fallback(VoidOnNotFoundOr404.class)
+   void delete(@EndpointParam URI operation);
+
+   /**
+    * Retrieves the list of operation resources available to the specified project.
+    * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not
+    * been set.
+    *
+    * @param token       marks the beginning of the next list page
+    * @param listOptions listing options
+    * @return a page of the list
+    */
+   @Named("GlobalOperations:list")
+   @GET
+   @Path("/projects/{project}/global/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseGlobalOperations.class)
+   @Fallback(EmptyListPageOnNotFoundOr404.class)
+   ListPage<Operation> listPage(@Nullable @QueryParam("pageToken") String token, ListOptions listOptions);
+
+   /**
+    * @see #list(org.jclouds.googlecomputeengine.options.ListOptions)
+    */
+   @Named("GlobalOperations:list")
+   @GET
+   @Path("/projects/{project}/global/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseGlobalOperations.class)
+   @Transform(ParseGlobalOperations.ToIteratorOfListPage.class)
+   @Fallback(EmptyIteratorOnNotFoundOr404.class)
+   Iterator<ListPage<Operation>> list();
+
+   /**
+    * @see #listPage(String, ListOptions)
+    */
+   @Named("GlobalOperations:list")
+   @GET
+   @Path("/projects/{project}/global/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseGlobalOperations.class)
+   @Transform(ParseGlobalOperations.ToIteratorOfListPage.class)
+   @Fallback(EmptyIteratorOnNotFoundOr404.class)
+   Iterator<ListPage<Operation>> list(ListOptions options);
+
+   /**
+    * Retrieves the list of operation resources available in the specified region.
+    * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not
+    * been set.
+    *
+    * @param token       marks the beginning of the next list page
+    * @param listOptions listing options
+    * @return a page of the list
+    */
+   @Named("RegionOperations:list")
+   @GET
+   @Path("/projects/{project}/regions/{region}/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseRegionOperations.class)
+   @Fallback(EmptyListPageOnNotFoundOr404.class)
+   ListPage<Operation> listPageInRegion(@PathParam("region") String region,
+                                        @Nullable @QueryParam("pageToken") String token, ListOptions listOptions);
+
+   /**
+    * @see #listInRegion(String, org.jclouds.googlecomputeengine.options.ListOptions)
+    */
+   @Named("RegionOperations:list")
+   @GET
+   @Path("/projects/{project}/regions/{region}/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseRegionOperations.class)
+   @Transform(ParseRegionOperations.ToIteratorOfListPage.class)
+   @Fallback(EmptyIteratorOnNotFoundOr404.class)
+   Iterator<ListPage<Operation>> listInRegion(@PathParam("region") String region);
+
+   /**
+    * @see #listPageInRegion(String, String, ListOptions)
+    */
+   @Named("RegionOperations:list")
+   @GET
+   @Path("/projects/{project}/regions/{region}/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseRegionOperations.class)
+   @Transform(ParseRegionOperations.ToIteratorOfListPage.class)
+   @Fallback(EmptyIteratorOnNotFoundOr404.class)
+   Iterator<ListPage<Operation>> listInRegion(@PathParam("region") String region, ListOptions options);
+
+   /**
+    * Retrieves the list of operation resources available in the specified zone.
+    * By default the list as a maximum size of 100, if no options are provided or ListOptions#getMaxResults() has not
+    * been set.
+    *
+    * @param token       marks the beginning of the next list page
+    * @param listOptions listing options
+    * @return a page of the list
+    */
+   @Named("ZoneOperations:list")
+   @GET
+   @Path("/projects/{project}/zones/{zone}/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseZoneOperations.class)
+   @Fallback(EmptyListPageOnNotFoundOr404.class)
+   ListPage<Operation> listPageInZone(@PathParam("zone") String zone,
+         @Nullable @QueryParam("pageToken") String token, ListOptions listOptions);
+
+   /**
+    * @see #listInZone(String, org.jclouds.googlecomputeengine.options.ListOptions)
+    */
+   @Named("ZoneOperations:list")
+   @GET
+   @Path("/projects/{project}/zones/{zone}/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseZoneOperations.class)
+   @Transform(ParseZoneOperations.ToIteratorOfListPage.class)
+   @Fallback(EmptyIteratorOnNotFoundOr404.class)
+   Iterator<ListPage<Operation>> listInZone(@PathParam("zone") String zone);
+
+   /**
+    * @see #listPageInZone(String, String, ListOptions)
+    */
+   @Named("ZoneOperations:list")
+   @GET
+   @Path("/projects/{project}/zones/{zone}/operations")
+   @OAuthScopes(COMPUTE_READONLY_SCOPE)
+   @ResponseParser(ParseZoneOperations.class)
+   @Transform(ParseZoneOperations.ToIteratorOfListPage.class)
+   @Fallback(EmptyIteratorOnNotFoundOr404.class)
+   Iterator<ListPage<Operation>> listInZone(@PathParam("zone") String zone, ListOptions options);
+}