Skip to content

Commit c1e71e1

Browse files
author
Ajay Kannan
committed
WIP
1 parent e7994eb commit c1e71e1

File tree

4 files changed

+109
-168
lines changed

4 files changed

+109
-168
lines changed

gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/LocalGcdHelper.java renamed to gcloud-java-datastore/src/main/java/com/google/gcloud/datastore/testing/LocalDatastoreHelper.java

+89-145
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import static com.google.common.base.MoreObjects.firstNonNull;
2020
import static com.google.common.base.Preconditions.checkArgument;
21-
import static java.nio.charset.StandardCharsets.UTF_8;
2221

2322
import com.google.common.base.Strings;
2423
import com.google.gcloud.AuthCredentials;
@@ -30,8 +29,6 @@
3029
import java.io.File;
3130
import java.io.FileInputStream;
3231
import java.io.FileOutputStream;
33-
import java.io.FileReader;
34-
import java.io.FileWriter;
3532
import java.io.IOException;
3633
import java.io.InputStream;
3734
import java.io.InputStreamReader;
@@ -54,10 +51,8 @@
5451
import java.security.NoSuchAlgorithmException;
5552
import java.util.ArrayList;
5653
import java.util.Arrays;
57-
import java.util.HashMap;
5854
import java.util.List;
5955
import java.util.Locale;
60-
import java.util.Map;
6156
import java.util.logging.Level;
6257
import java.util.logging.Logger;
6358
import java.util.regex.Pattern;
@@ -67,18 +62,9 @@
6762
/**
6863
* Utility to start and stop local Google Cloud Datastore process.
6964
*/
70-
public class LocalGcdHelper {
71-
private static final Logger log = Logger.getLogger(LocalGcdHelper.class.getName());
72-
73-
private final String projectId;
74-
private Path gcdPath;
75-
private Process startProcess;
76-
private ProcessStreamReader processReader;
77-
private ProcessErrorStreamReader processErrorReader;
78-
private final int port;
79-
80-
public static final String DEFAULT_PROJECT_ID = "projectid1";
81-
public static final int DEFAULT_PORT = 8080;
65+
public class LocalDatastoreHelper {
66+
private static final Logger log = Logger.getLogger(LocalDatastoreHelper.class.getName());
67+
private static final double DEFAULT_CONSISTENCY = 0.9;
8268
private static final String GCD_VERSION = "v1beta2";
8369
private static final String GCD_BUILD = "rev1-2.1.2b";
8470
private static final String GCD_BASENAME = "gcd-" + GCD_VERSION + "-" + GCD_BUILD;
@@ -88,7 +74,13 @@ public class LocalGcdHelper {
8874
private static final String GCLOUD = "gcloud";
8975
private static final Path INSTALLED_GCD_PATH;
9076
private static final String GCD_VERSION_PREFIX = "gcd-emulator ";
91-
private static final double DEFAULT_CONSISTENCY = 0.9;
77+
78+
private final String projectId;
79+
private Path gcdPath;
80+
private Process startProcess;
81+
private ProcessStreamReader processReader;
82+
private ProcessErrorStreamReader processErrorReader;
83+
private final int port;
9284

9385
static {
9486
INSTALLED_GCD_PATH = installedGcdPath();
@@ -103,14 +95,6 @@ public class LocalGcdHelper {
10395
}
10496
}
10597

106-
public static int findAvailablePort(int defaultPort) {
107-
try (ServerSocket tempSocket = new ServerSocket(0)) {
108-
return tempSocket.getLocalPort();
109-
} catch (IOException e) {
110-
return defaultPort;
111-
}
112-
}
113-
11498
private static Path installedGcdPath() {
11599
String gcloudExecutableName;
116100
if (isWindows()) {
@@ -390,56 +374,6 @@ public static CommandWrapper create() {
390374
}
391375
}
392376

393-
public LocalGcdHelper(String projectId, int port) {
394-
this.projectId = projectId;
395-
this.port = port;
396-
}
397-
398-
/**
399-
* Returns a {@link DatastoreOptions} instance that sets the host to use the Datastore emulator
400-
* on localhost.
401-
*/
402-
public DatastoreOptions options() {
403-
return DatastoreOptions.builder()
404-
.projectId(projectId)
405-
.host("http://localhost:" + Integer.toString(port))
406-
.authCredentials(AuthCredentials.noAuth())
407-
.build();
408-
}
409-
410-
/**
411-
* Starts the local datastore for the specific project.
412-
*
413-
* This will unzip the gcd tool, create the project and start it.
414-
* All content is written to a temporary directory that will be deleted when
415-
* {@link #stop()} is called or when the program terminates) to make sure that no left-over
416-
* data from prior runs is used.
417-
*
418-
* @param consistency the fraction of job application attempts that will succeed, with 0.0
419-
* resulting in no attempts succeeding, and 1.0 resulting in all attempts succeeding. Defaults
420-
* to 0.9. Note that setting this to 1.0 may mask incorrect assumptions about the consistency
421-
* of non-ancestor queries; non-ancestor queries are eventually consistent.
422-
*/
423-
public void start(double consistency) throws IOException, InterruptedException {
424-
// send a quick request in case we have a hanging process from a previous run
425-
checkArgument(consistency >= 0.0 && consistency <= 1.0, "Consistency must be between 0 and 1");
426-
sendQuitRequest(port);
427-
// Each run is associated with its own folder that is deleted once test completes.
428-
gcdPath = Files.createTempDirectory("gcd");
429-
File gcdFolder = gcdPath.toFile();
430-
gcdFolder.deleteOnExit();
431-
432-
Path gcdExecutablePath;
433-
// If cloud is available we use it, otherwise we download and start gcd
434-
if (INSTALLED_GCD_PATH == null) {
435-
downloadGcd();
436-
gcdExecutablePath = gcdPath.resolve(GCD_BASENAME);
437-
} else {
438-
gcdExecutablePath = INSTALLED_GCD_PATH;
439-
}
440-
startGcd(gcdExecutablePath, consistency);
441-
}
442-
443377
private void downloadGcd() throws IOException {
444378
// check if we already have a local copy of the gcd utility and download it if not.
445379
File gcdZipFile = new File(System.getProperty("java.io.tmpdir"), GCD_FILENAME);
@@ -603,83 +537,93 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
603537
});
604538
}
605539

606-
public static LocalGcdHelper start(String projectId, int port, double consistency)
540+
private LocalDatastoreHelper(String projectId) {
541+
this.projectId = projectId;
542+
this.port = findAvailablePort();
543+
}
544+
545+
private static int findAvailablePort() {
546+
try (ServerSocket tempSocket = new ServerSocket(0)) {
547+
return tempSocket.getLocalPort();
548+
} catch (IOException e) {
549+
return -1;
550+
}
551+
}
552+
553+
/**
554+
* Returns a {@link DatastoreOptions} instance that sets the host to use the Datastore emulator
555+
* on localhost.
556+
*/
557+
public DatastoreOptions options() {
558+
return DatastoreOptions.builder()
559+
.projectId(projectId)
560+
.host("http://localhost:" + Integer.toString(port))
561+
.authCredentials(AuthCredentials.noAuth())
562+
.build();
563+
}
564+
565+
/**
566+
* Returns the project ID associated with this local Datastore emulator.
567+
*/
568+
public String projectId() {
569+
return projectId;
570+
}
571+
572+
/**
573+
* Returns the port on localhost to which the local Datastore listens for requests.
574+
*/
575+
public int port() {
576+
return port;
577+
}
578+
579+
/**
580+
* Starts the local Datastore for the specific project.
581+
*
582+
* This will unzip the gcd tool, create the project and start it. All content is written to a
583+
* temporary directory that will be deleted when {@link #stop()} is called (or when the program
584+
* terminates) to make sure that no left-over data from prior runs is used.
585+
*
586+
* @param consistency the fraction of Datastore writes that are immediately visible to global
587+
* queries, with 0.0 resulting in no attempts succeeding, and 1.0 resulting in all attempts succeeding. Note
588+
* that setting this to 1.0 may mask incorrect assumptions about the consistency of
589+
* non-ancestor queries; non-ancestor queries are eventually consistent.
590+
*/
591+
public static LocalDatastoreHelper start(String projectId, double consistency)
607592
throws IOException, InterruptedException {
608-
LocalGcdHelper helper = new LocalGcdHelper(projectId, port);
593+
LocalDatastoreHelper helper = new LocalDatastoreHelper(projectId);
609594
helper.start(consistency);
610595
return helper;
611596
}
612597

613-
public static void main(String... args) throws IOException, InterruptedException {
614-
Map<String, String> parsedArgs = parseArgs(args);
615-
String action = parsedArgs.get("action");
616-
int port =
617-
(parsedArgs.get("port") == null) ? DEFAULT_PORT : Integer.parseInt(parsedArgs.get("port"));
618-
switch (action) {
619-
case "START":
620-
if (!isActive(DEFAULT_PROJECT_ID, port)) {
621-
double consistency = parsedArgs.get("consistency") == null
622-
? DEFAULT_CONSISTENCY : Double.parseDouble(parsedArgs.get("consistency"));
623-
LocalGcdHelper helper = start(DEFAULT_PROJECT_ID, port, consistency);
624-
try (FileWriter writer = new FileWriter(".local_gcd_helper")) {
625-
writer.write(helper.gcdPath.toAbsolutePath().toString() + System.lineSeparator());
626-
writer.write(Integer.toString(port));
627-
}
628-
}
629-
return;
630-
case "STOP":
631-
File file = new File(".local_gcd_helper");
632-
String path = null;
633-
boolean fileExists = file.exists();
634-
if (fileExists) {
635-
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
636-
path = reader.readLine();
637-
port = Integer.parseInt(reader.readLine());
638-
}
639-
}
640-
sendQuitRequest(port);
641-
if (fileExists) {
642-
deleteRecurse(Paths.get(path));
643-
file.delete();
644-
}
645-
return;
646-
default:
647-
break;
648-
}
598+
/**
599+
* Starts the local Datastore for the specific project using a default consistency setting of 0.9.
600+
*
601+
* This will unzip the gcd tool, create the project and start it. All content is written to a
602+
* temporary directory that will be deleted when {@link #stop()} is called (or when the program
603+
* terminates) to make sure that no left-over data from prior runs is used.
604+
*/
605+
public static LocalDatastoreHelper start(String projectId)
606+
throws IOException, InterruptedException {
607+
return start(projectId, DEFAULT_CONSISTENCY);
649608
}
650609

651-
private static Map<String, String> parseArgs(String[] args) {
652-
Map<String, String> parsedArgs = new HashMap<String, String>();
653-
for (String arg : args) {
654-
if (arg.startsWith("--port=")) {
655-
parsedArgs.put("port", arg.substring("--port=".length()));
656-
} else if (arg.startsWith("--consistency=")) {
657-
parsedArgs.put("consistency", arg.substring("--consistency=".length()));
658-
} else if (arg.equals("START") || arg.equals("STOP")) {
659-
parsedArgs.put("action", arg);
660-
} else {
661-
throw new RuntimeException("Only accepts START, STOP, --port=<port #> and "
662-
+ "--consistency=<double in range [0,1]> as arguments.");
663-
}
664-
}
665-
if (parsedArgs.get("action") == null) {
666-
throw new RuntimeException("EXPECTING START | STOP");
667-
}
668-
return parsedArgs;
669-
}
610+
private void start(double consistency) throws IOException, InterruptedException {
611+
// send a quick request in case we have a hanging process from a previous run
612+
checkArgument(consistency >= 0.0 && consistency <= 1.0, "Consistency must be between 0 and 1");
613+
sendQuitRequest(port);
614+
// Each run is associated with its own folder that is deleted once test completes.
615+
gcdPath = Files.createTempDirectory("gcd");
616+
File gcdFolder = gcdPath.toFile();
617+
gcdFolder.deleteOnExit();
670618

671-
public static boolean isActive(String projectId, int port) {
672-
try {
673-
StringBuilder urlBuilder = new StringBuilder("http://localhost:").append(port);
674-
urlBuilder.append("/datastore/v1beta2/datasets/").append(projectId).append("/lookup");
675-
URL url = new URL(urlBuilder.toString());
676-
try (BufferedReader reader =
677-
new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) {
678-
return "Valid RPC".equals(reader.readLine());
679-
}
680-
} catch (IOException ignore) {
681-
// assume not active
682-
return false;
619+
Path gcdExecutablePath;
620+
// If cloud is available we use it, otherwise we download and start gcd
621+
if (INSTALLED_GCD_PATH == null) {
622+
downloadGcd();
623+
gcdExecutablePath = gcdPath.resolve(GCD_BASENAME);
624+
} else {
625+
gcdExecutablePath = INSTALLED_GCD_PATH;
683626
}
627+
startGcd(gcdExecutablePath, consistency);
684628
}
685629
}

gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreOptionsTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
import com.google.gcloud.datastore.spi.DatastoreRpc;
2626
import com.google.gcloud.datastore.spi.DatastoreRpcFactory;
27-
import com.google.gcloud.datastore.testing.LocalGcdHelper;
27+
import com.google.gcloud.datastore.testing.LocalDatastoreHelper;
2828

2929
import org.easymock.EasyMock;
3030
import org.junit.Before;
@@ -33,7 +33,7 @@
3333
public class DatastoreOptionsTest {
3434

3535
private static final String PROJECT_ID = "project_id";
36-
private static final int PORT = LocalGcdHelper.findAvailablePort(LocalGcdHelper.DEFAULT_PORT);
36+
private static final int PORT = LocalDatastoreHelper.findAvailablePort(LocalDatastoreHelper.DEFAULT_PORT);
3737
private DatastoreRpcFactory datastoreRpcFactory;
3838
private DatastoreRpc datastoreRpc;
3939
private DatastoreOptions.Builder options;

gcloud-java-datastore/src/test/java/com/google/gcloud/datastore/DatastoreTest.java

+4-7
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import com.google.gcloud.datastore.StructuredQuery.PropertyFilter;
4040
import com.google.gcloud.datastore.spi.DatastoreRpc;
4141
import com.google.gcloud.datastore.spi.DatastoreRpcFactory;
42-
import com.google.gcloud.datastore.testing.LocalGcdHelper;
42+
import com.google.gcloud.datastore.testing.LocalDatastoreHelper;
4343
import com.google.protobuf.ByteString;
4444

4545
import org.easymock.EasyMock;
@@ -63,7 +63,7 @@
6363
@RunWith(JUnit4.class)
6464
public class DatastoreTest {
6565

66-
private static final String PROJECT_ID = LocalGcdHelper.DEFAULT_PROJECT_ID;
66+
private static final String PROJECT_ID = "projectid1";
6767
private static final String KIND1 = "kind1";
6868
private static final String KIND2 = "kind2";
6969
private static final String KIND3 = "kind3";
@@ -110,17 +110,14 @@ public class DatastoreTest {
110110
private DatastoreOptions options;
111111
private Datastore datastore;
112112

113-
private static LocalGcdHelper gcdHelper;
114-
private static final int PORT = LocalGcdHelper.findAvailablePort(LocalGcdHelper.DEFAULT_PORT);
113+
private static LocalDatastoreHelper gcdHelper;
115114

116115
@Rule
117116
public ExpectedException thrown = ExpectedException.none();
118117

119118
@BeforeClass
120119
public static void beforeClass() throws IOException, InterruptedException {
121-
if (!LocalGcdHelper.isActive(PROJECT_ID, PORT)) {
122-
gcdHelper = LocalGcdHelper.start(PROJECT_ID, PORT, 1.0);
123-
}
120+
gcdHelper = LocalDatastoreHelper.start(PROJECT_ID, 1.0);
124121
}
125122

126123
@Before

0 commit comments

Comments
 (0)