From 577458f009374ed9bfa52afb71a0d859b06c0825 Mon Sep 17 00:00:00 2001
From: Ajay Kannan <ajaykannan@google.com>
Date: Thu, 31 Mar 2016 13:40:29 -0700
Subject: [PATCH] Add create and start in LocalDatastoreHelper, minor fixes to
 docs and variable naming

---
 TESTING.md                                    | 25 +++++++----
 .../gcloud/bigquery/it/ITBigQueryTest.java    |  4 +-
 .../testing/LocalDatastoreHelper.java         | 44 ++++++++++---------
 .../datastore/testing/package-info.java       |  3 +-
 .../datastore/DatastoreOptionsTest.java       |  3 +-
 .../gcloud/datastore/DatastoreTest.java       | 10 ++---
 .../datastore/LocalDatastoreHelperTest.java   | 12 +++--
 .../gcloud/dns/testing/package-info.java      |  2 +-
 .../examples/datastore/DatastoreExample.java  | 10 ++---
 .../resourcemanager/testing/package-info.java |  2 +-
 .../storage/RemoteStorageHelperTest.java      |  4 +-
 .../gcloud/storage/it/ITStorageTest.java      |  4 +-
 12 files changed, 67 insertions(+), 56 deletions(-)

diff --git a/TESTING.md b/TESTING.md
index 41335aff26de..5c8bd810cfee 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -13,19 +13,23 @@ This library provides tools to help write tests for code that uses the following
 
 You can test against a temporary local Datastore by following these steps:
 
-1. Start the local Datastore emulator before running your tests using `LocalDatastoreHelper`'s `start` method. This will create a temporary folder on your computer and bind a port for communication with the local datastore. There are two optional arguments for `start`: project ID and consistency. The consistency setting controls the fraction of Datastore writes that are immediately visible in global queries.
+1. Start the local Datastore emulator before running your tests using `LocalDatastoreHelper`'s `create` and `start` methods. This will create a temporary folder on your computer and bind a port for communication with the local Datastore. There are two optional arguments for `create`: project ID and consistency. The consistency setting controls the fraction of Datastore writes that are immediately visible in global queries.
   ```java
-  // Use defaults for project ID and consistency
-  LocalDatastoreHelper helper = LocalDatastoreHelper.start();
+  // Use a placeholder project ID and the default consistency setting of 0.9
+  LocalDatastoreHelper helper = LocalDatastoreHelper.create();
   // or explicitly provide them
-  helper = LocalDatastoreHelper.start("my-project-id", 0.6);
+  helper = LocalDatastoreHelper.create("my-project-id", 0.6);
+  
+  helper.start(); // Starts the local Datastore emulator in a separate process
   ```
 
-2. In your program, create and use a `Datastore` object with the options given by the `LocalDatastoreHelper` instance.  For example:
+2. Create and use a `Datastore` object with the options given by the `LocalDatastoreHelper` instance.  For example:
   ```java
   Datastore localDatastore = helper.options().service();
   ```
   
+  Note that you must call `start` before `options()`; otherwise, you will see an `IOException` regarding a refused connection.
+  
 3. Run your tests.
 
 4. Stop the local datastore emulator by calling the `stop()` method, like so:
@@ -38,14 +42,19 @@ You can test against a temporary local Datastore by following these steps:
 You can test against a remote Datastore emulator as well.  To do this, set the `DatastoreOptions` project endpoint to the hostname of the remote machine, like the example below.
 
   ```java
-  DatastoreOptions options = LocalDatastoreHelper.options()
-      .toBuilder()
+  DatastoreOptions options = DatastoreOptions.builder()
+      .projectId("my-project-id") // must match project ID specified on remote machine
       .host("http://<hostname of machine>:<port>")
+      .authCredentials(AuthCredentials.noAuth())
       .build();
   Datastore localDatastore = options.service();
   ```
 
-Note that the remote Datastore emulator must be running before your tests are run.
+Note that the remote Datastore emulator must be running before running the code above. We recommend that you start the emulator on the remote machine using the [Google Cloud SDK](https://cloud.google.com/sdk/gcloud/reference/beta/emulators/datastore/) from command line, as shown below:
+
+```
+gcloud beta emulators datastore start
+```
 
 ### Testing code that uses Storage
 
diff --git a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/it/ITBigQueryTest.java b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/it/ITBigQueryTest.java
index b40e026feb82..e48ca99e41b2 100644
--- a/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/it/ITBigQueryTest.java
+++ b/gcloud-java-bigquery/src/test/java/com/google/gcloud/bigquery/it/ITBigQueryTest.java
@@ -171,9 +171,9 @@ public class ITBigQueryTest {
   @BeforeClass
   public static void beforeClass() throws InterruptedException {
     RemoteBigQueryHelper bigqueryHelper = RemoteBigQueryHelper.create();
-    RemoteStorageHelper gcsHelper = RemoteStorageHelper.create();
+    RemoteStorageHelper storageHelper = RemoteStorageHelper.create();
     bigquery = bigqueryHelper.options().service();
-    storage = gcsHelper.options().service();
+    storage = storageHelper.options().service();
     storage.create(BucketInfo.of(BUCKET));
     storage.create(BlobInfo.builder(BUCKET, LOAD_FILE).contentType("text/plain").build(),
         CSV_CONTENT.getBytes(StandardCharsets.UTF_8));
diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/LocalDatastoreHelper.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/LocalDatastoreHelper.java
index c7587b77747f..5e2ac6f7d839 100644
--- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/LocalDatastoreHelper.java
+++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/LocalDatastoreHelper.java
@@ -545,7 +545,7 @@ private LocalDatastoreHelper(String projectId, double consistency) {
     this.port = findAvailablePort();
   }
 
-  private static int findAvailablePort() {
+  public static int findAvailablePort() {
     try (ServerSocket tempSocket = new ServerSocket(0)) {
       return tempSocket.getLocalPort();
     } catch (IOException e) {
@@ -555,7 +555,7 @@ private static int findAvailablePort() {
 
   /**
    * Returns a {@link DatastoreOptions} instance that sets the host to use the Datastore emulator
-   * on localhost.
+   * on localhost. This should only be called after calling {@link #start}.
    */
   public DatastoreOptions options() {
     return DatastoreOptions.builder()
@@ -587,36 +587,38 @@ public double consistency() {
   }
 
   /**
-   * Starts the local Datastore for the specific project.
-   *
-   * This will unzip the gcd tool, create the project and start it. All content is written to a
-   * temporary directory that will be deleted when {@link #stop()} is called (or when the program
-   * terminates) to make sure that no left-over data from prior runs is used.
+   * Creates a local Datastore helper with the specified settings for project ID and consistency.
    *
    * @param consistency the fraction of Datastore writes that are immediately visible to global
-   *     queries, with 0.0 resulting in no attempts succeeding, and 1.0 resulting in all attempts succeeding. Note
-   *     that setting this to 1.0 may mask incorrect assumptions about the consistency of
-   *     non-ancestor queries; non-ancestor queries are eventually consistent.
+   *     queries, with 0.0 meaning no writes are immediately visible and 1.0 meaning all writes
+   *     are immediately visible. Note that setting this to 1.0 may mask incorrect assumptions
+   *     about the consistency of non-ancestor queries; non-ancestor queries are eventually
+   *     consistent.
    */
-  public static LocalDatastoreHelper start(String projectId, double consistency)
-      throws IOException, InterruptedException {
+  public static LocalDatastoreHelper create(String projectId, double consistency) {
     LocalDatastoreHelper helper = new LocalDatastoreHelper(projectId, consistency);
-    helper.findAndStartGcd();
     return helper;
   }
 
   /**
-   * Starts the local Datastore using defaults for project ID and consistency setting of 0.9.
-   *
-   * This will unzip the gcd tool, create the project and start it. All content is written to a
-   * temporary directory that will be deleted when {@link #stop()} is called (or when the program
-   * terminates) to make sure that no left-over data from prior runs is used.
+   * Creates a local Datastore helper with a placeholder project ID and the default consistency
+   * setting of 0.9. Consistency refers to the fraction of Datastore writes that are immediately
+   * visible to global queries, with 0.0 meaning no writes are immediately visible and 1.0 meaning
+   * all writes are immediately visible.
    */
-  public static LocalDatastoreHelper start() throws IOException, InterruptedException {
-    return start(DEFAULT_PROJECT_ID, DEFAULT_CONSISTENCY);
+  public static LocalDatastoreHelper create() {
+    return create(DEFAULT_PROJECT_ID, DEFAULT_CONSISTENCY);
   }
 
-  private void findAndStartGcd() throws IOException, InterruptedException {
+  /**
+   * Starts the local Datastore emulator. Leftover data from previous uses of the emulator will be
+   * removed.
+   *
+   * @throws InterruptedException if emulator-related tasks are interrupted
+   * @throws IOException if there are socket exceptions or issues creating/deleting the temporary
+   * data folder
+   */
+  public void start() throws IOException, InterruptedException {
     // send a quick request in case we have a hanging process from a previous run
     checkArgument(consistency >= 0.0 && consistency <= 1.0, "Consistency must be between 0 and 1");
     sendQuitRequest(port);
diff --git a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/package-info.java b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/package-info.java
index ab78449b3176..fae9860275c6 100644
--- a/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/package-info.java
+++ b/gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/package-info.java
@@ -20,7 +20,8 @@
  * <p>A simple usage example:
  * <p>Before the test:
  * <pre> {@code
- * LocalDatastoreHelper helper = LocalDatastoreHelper.start();
+ * LocalDatastoreHelper helper = LocalDatastoreHelper.create();
+ * helper.start();
  * Datastore localDatastore = helper.options().service();
  * } </pre>
  *
diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreOptionsTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreOptionsTest.java
index e02c42398056..92d449f89d35 100644
--- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreOptionsTest.java
+++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreOptionsTest.java
@@ -24,6 +24,7 @@
 
 import com.google.gcloud.datastore.spi.DatastoreRpc;
 import com.google.gcloud.datastore.spi.DatastoreRpcFactory;
+import com.google.gcloud.datastore.testing.LocalDatastoreHelper;
 
 import org.easymock.EasyMock;
 import org.junit.Before;
@@ -32,7 +33,7 @@
 public class DatastoreOptionsTest {
 
   private static final String PROJECT_ID = "project-id";
-  private static final int PORT = 8080;
+  private static final int PORT = LocalDatastoreHelper.findAvailablePort();
   private DatastoreRpcFactory datastoreRpcFactory;
   private DatastoreRpc datastoreRpc;
   private DatastoreOptions.Builder options;
diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java
index cd4adedec75a..1c2499531464 100644
--- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java
+++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java
@@ -110,19 +110,19 @@ public class DatastoreTest {
   private DatastoreOptions options;
   private Datastore datastore;
 
-  private static LocalDatastoreHelper gcdHelper;
+  private static LocalDatastoreHelper helper = LocalDatastoreHelper.create(PROJECT_ID, 1.0);
 
   @Rule
   public ExpectedException thrown = ExpectedException.none();
 
   @BeforeClass
   public static void beforeClass() throws IOException, InterruptedException {
-    gcdHelper = LocalDatastoreHelper.start(PROJECT_ID, 1.0);
+    helper.start();
   }
 
   @Before
   public void setUp() {
-    options = gcdHelper.options().toBuilder().retryParams(RetryParams.noRetries()).build();
+    options = helper.options().toBuilder().retryParams(RetryParams.noRetries()).build();
     datastore = options.service();
     StructuredQuery<Key> query = Query.keyQueryBuilder().build();
     QueryResults<Key> result = datastore.run(query);
@@ -132,8 +132,8 @@ public void setUp() {
 
   @AfterClass
   public static void afterClass() throws IOException, InterruptedException {
-    if (gcdHelper != null) {
-      gcdHelper.stop();
+    if (helper != null) {
+      helper.stop();
     }
   }
 
diff --git a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/LocalDatastoreHelperTest.java b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/LocalDatastoreHelperTest.java
index 92d3e6a14d22..2bc2c60f76e2 100644
--- a/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/LocalDatastoreHelperTest.java
+++ b/gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/LocalDatastoreHelperTest.java
@@ -36,24 +36,22 @@ public class LocalDatastoreHelperTest {
   private static final double TOLERANCE = 0.00001;
 
   @Test
-  public void testStart() throws IOException, InterruptedException {
-    LocalDatastoreHelper helper = LocalDatastoreHelper.start(PROJECT_ID, 0.75);
+  public void testCreate() {
+    LocalDatastoreHelper helper = LocalDatastoreHelper.create(PROJECT_ID, 0.75);
     assertTrue(Math.abs(0.75 - helper.consistency()) < TOLERANCE);
     assertEquals(PROJECT_ID, helper.projectId());
-    helper.stop();
-    helper = LocalDatastoreHelper.start();
+    helper = LocalDatastoreHelper.create();
     assertTrue(Math.abs(0.9 - helper.consistency()) < TOLERANCE);
     assertEquals(LocalDatastoreHelper.DEFAULT_PROJECT_ID, helper.projectId());
-    helper.stop();
   }
 
   @Test
   public void testOptions() throws IOException, InterruptedException {
-    LocalDatastoreHelper helper = LocalDatastoreHelper.start();
+    LocalDatastoreHelper helper = LocalDatastoreHelper.create();
+    helper.start();
     DatastoreOptions options = helper.options();
     assertEquals(LocalDatastoreHelper.DEFAULT_PROJECT_ID, options.projectId());
     assertEquals("http://localhost:" + helper.port(), options.host());
     assertSame(AuthCredentials.noAuth(), options.authCredentials());
-    helper.stop();
   }
 }
diff --git a/gcloud-java-dns/src/main/java/com/google/gcloud/dns/testing/package-info.java b/gcloud-java-dns/src/main/java/com/google/gcloud/dns/testing/package-info.java
index a0a0c593c2b7..85c332e56dd8 100644
--- a/gcloud-java-dns/src/main/java/com/google/gcloud/dns/testing/package-info.java
+++ b/gcloud-java-dns/src/main/java/com/google/gcloud/dns/testing/package-info.java
@@ -24,8 +24,8 @@
  * // request processing synchronous.
  * long delay = 0;
  * LocalDnsHelper dnsHelper = LocalDnsHelper.create(delay);
- * Dns dns = dnsHelper.options().service();
  * dnsHelper.start();
+ * Dns dns = dnsHelper.options().service();
  * }</pre>
  *
  * <p>After the test:
diff --git a/gcloud-java-examples/src/main/java/com/google/gcloud/examples/datastore/DatastoreExample.java b/gcloud-java-examples/src/main/java/com/google/gcloud/examples/datastore/DatastoreExample.java
index cc4331734200..00cfa90325c5 100644
--- a/gcloud-java-examples/src/main/java/com/google/gcloud/examples/datastore/DatastoreExample.java
+++ b/gcloud-java-examples/src/main/java/com/google/gcloud/examples/datastore/DatastoreExample.java
@@ -182,16 +182,14 @@ public String getRequiredParams() {
 
   public static void main(String... args) {
     String projectId = args.length > 0 ? args[0] : null;
-    // If you want to access a local Datastore running via the gcd sdk, do
+    // If you want to access a local Datastore running via the Google Cloud SDK, do
     //   DatastoreOptions options = DatastoreOptions.builder()
     //       .projectId(projectId)
     //       .namespace(NAMESPACE)
-    //       .host("http://localhost:8080")
+    //       .host("http://localhost:8080") // change 8080 to the port that the emulator listens to
     //       .build();
-    DatastoreOptions options = DatastoreOptions.builder()
-        .projectId(projectId)
-        .namespace(NAMESPACE)
-        .build();
+    DatastoreOptions options =
+        DatastoreOptions.builder().projectId(projectId).namespace(NAMESPACE).build();
     String name = args.length > 1 ? args[1] : System.getProperty("user.name");
     Datastore datastore = options.service();
     KeyFactory keyFactory = datastore.newKeyFactory().kind(USER_KIND);
diff --git a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/package-info.java b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/package-info.java
index b0165c1ddd9d..e00b6eda1822 100644
--- a/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/package-info.java
+++ b/gcloud-java-resourcemanager/src/main/java/com/google/gcloud/resourcemanager/testing/package-info.java
@@ -21,8 +21,8 @@
  * Before the test:
  * <pre> {@code
  * LocalResourceManagerHelper resourceManagerHelper = LocalResourceManagerHelper.create();
- * ResourceManager resourceManager = resourceManagerHelper.options().service();
  * resourceManagerHelper.start();
+ * ResourceManager resourceManager = resourceManagerHelper.options().service();
  * }</pre>
  *
  * <p>After the test:
diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteStorageHelperTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteStorageHelperTest.java
index 2690942d1a4a..0702d8aba65f 100644
--- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteStorageHelperTest.java
+++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/RemoteStorageHelperTest.java
@@ -17,6 +17,7 @@
 package com.google.gcloud.storage;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import com.google.common.collect.ImmutableList;
@@ -139,7 +140,8 @@ public void testForceDeleteTimeout() throws InterruptedException, ExecutionExcep
     }
     EasyMock.expect(storageMock.delete(BUCKET_NAME)).andThrow(RETRYABLE_EXCEPTION).anyTimes();
     EasyMock.replay(storageMock);
-    assertTrue(!RemoteStorageHelper.forceDelete(storageMock, BUCKET_NAME, 50, TimeUnit.MICROSECONDS));
+    assertFalse(
+        RemoteStorageHelper.forceDelete(storageMock, BUCKET_NAME, 50, TimeUnit.MICROSECONDS));
     EasyMock.verify(storageMock);
   }
 
diff --git a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/it/ITStorageTest.java b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/it/ITStorageTest.java
index 491ddd433499..3ea79a0b6860 100644
--- a/gcloud-java-storage/src/test/java/com/google/gcloud/storage/it/ITStorageTest.java
+++ b/gcloud-java-storage/src/test/java/com/google/gcloud/storage/it/ITStorageTest.java
@@ -85,8 +85,8 @@ public class ITStorageTest {
 
   @BeforeClass
   public static void beforeClass() {
-    RemoteStorageHelper gcsHelper = RemoteStorageHelper.create();
-    storage = gcsHelper.options().service();
+    RemoteStorageHelper helper = RemoteStorageHelper.create();
+    storage = helper.options().service();
     storage.create(BucketInfo.of(BUCKET));
   }