Skip to content

Commit

Permalink
Add create and start in LocalDatastoreHelper, minor fixes to docs and…
Browse files Browse the repository at this point in the history
… variable naming
  • Loading branch information
Ajay Kannan committed Mar 31, 2016
1 parent 7edd544 commit 577458f
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 56 deletions.
25 changes: 17 additions & 8 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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()
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand Down

0 comments on commit 577458f

Please sign in to comment.