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://:") + .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 @@ *

A simple usage example: *

Before the test: *

 {@code
- * LocalDatastoreHelper helper = LocalDatastoreHelper.start();
+ * LocalDatastoreHelper helper = LocalDatastoreHelper.create();
+ * helper.start();
  * Datastore localDatastore = helper.options().service();
  * } 
* 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 query = Query.keyQueryBuilder().build(); QueryResults 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(); * } * *

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: *

 {@code
  * LocalResourceManagerHelper resourceManagerHelper = LocalResourceManagerHelper.create();
- * ResourceManager resourceManager = resourceManagerHelper.options().service();
  * resourceManagerHelper.start();
+ * ResourceManager resourceManager = resourceManagerHelper.options().service();
  * }
* *

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)); }