Skip to content

Commit 1c52730

Browse files
committed
Refactor process invocation for gcd in tests. Restored Windows support.
1 parent 47632ab commit 1c52730

1 file changed

Lines changed: 123 additions & 37 deletions

File tree

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

Lines changed: 123 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@
4747
import java.nio.file.attribute.BasicFileAttributes;
4848
import java.security.MessageDigest;
4949
import java.security.NoSuchAlgorithmException;
50+
import java.util.ArrayList;
51+
import java.util.Arrays;
52+
import java.util.List;
5053
import java.util.Locale;
5154
import java.util.regex.Pattern;
5255
import java.util.zip.ZipEntry;
@@ -56,20 +59,22 @@
5659
* Utility to start and stop local Google Cloud Datastore process.
5760
*/
5861
public class LocalGcdHelper {
59-
62+
6063
private final String projectId;
6164
private Path gcdPath;
6265
private ProcessStreamReader processReader;
6366

6467
public static final String DEFAULT_PROJECT_ID = "projectid1";
6568
public static final int PORT = 8080;
66-
private static final String GCD = "gcd-v1beta2-rev1-2.1.2b";
6769
private static final String GCD_VERSION = "v1beta2";
68-
private static final String GCD_FILENAME = GCD + ".zip";
70+
private static final String GCD_BUILD = "rev1-2.1.2b";
71+
private static final String GCD_BASENAME = "gcd-" + GCD_VERSION + "-" + GCD_BUILD;
72+
private static final String GCD_FILENAME = GCD_BASENAME + ".zip";
6973
private static final String MD5_CHECKSUM = "d84384cdfa8658e1204f4f8be51300e8";
7074
private static final URL GCD_URL;
7175
private static final String GCLOUD = "gcloud";
7276
private static final Path INSTALLED_GCD_PATH;
77+
private static final String GCD_VERSION_PREFIX = "gcd-emulator ";
7378

7479
static {
7580
INSTALLED_GCD_PATH = installedGcdPath();
@@ -85,7 +90,13 @@ public class LocalGcdHelper {
8590
}
8691

8792
private static Path installedGcdPath() {
88-
Path gcloudPath = executablePath(GCLOUD);
93+
String gcloudExecutableName;
94+
if (isWindows()) {
95+
gcloudExecutableName = GCLOUD + ".cmd";
96+
} else {
97+
gcloudExecutableName = GCLOUD;
98+
}
99+
Path gcloudPath = executablePath(gcloudExecutableName);
89100
gcloudPath = (gcloudPath == null) ? null : gcloudPath.getParent();
90101
if (gcloudPath == null) {
91102
return null;
@@ -105,19 +116,18 @@ private static Path installedGcdPath() {
105116
}
106117

107118
private static String installedGcdVersion() throws IOException, InterruptedException {
108-
ProcessBuilder processBuilder = new ProcessBuilder()
109-
.redirectErrorStream(true);
119+
CommandWrapper gcloudCommand;
110120
if (isWindows()) {
111-
processBuilder.command("cmd", "/C", "gcloud", "version");
121+
gcloudCommand = CommandWrapper.cmd();
112122
} else {
113-
processBuilder.command("bash", "gcloud", "version");
123+
gcloudCommand = CommandWrapper.bash();
114124
}
115-
Process process = processBuilder.start();
125+
Process process = gcloudCommand.command("gcloud", "version").redirectErrorStream().start();
116126
process.waitFor();
117127
try (BufferedReader reader =
118128
new BufferedReader(new InputStreamReader(process.getInputStream()))) {
119129
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
120-
if (line.startsWith("gcd-emulator")) {
130+
if (line.startsWith(GCD_VERSION_PREFIX)) {
121131
String[] lineComponents = line.split(" ");
122132
if (lineComponents.length > 1) {
123133
return lineComponents[1];
@@ -126,7 +136,6 @@ private static String installedGcdVersion() throws IOException, InterruptedExcep
126136
}
127137
return null;
128138
}
129-
130139
}
131140

132141
private static Path executablePath(String cmd) {
@@ -185,6 +194,84 @@ public static ProcessStreamReader start(Process process, String blockUntil) thro
185194
return thread;
186195
}
187196
}
197+
198+
private static class CommandWrapper {
199+
200+
private final List<String> prefix;
201+
private List<String> command;
202+
private String nullFilename;
203+
private boolean redirectOutputToNull;
204+
private boolean redirectErrorStream;
205+
private boolean redirectErrorInherit;
206+
private Path directory;
207+
208+
private CommandWrapper() {
209+
this.prefix = new ArrayList<>();
210+
}
211+
212+
public CommandWrapper command(String... command) {
213+
this.command = new ArrayList<>(command.length + this.prefix.size());
214+
this.command.addAll(prefix);
215+
this.command.addAll(Arrays.asList(command));
216+
return this;
217+
}
218+
219+
public CommandWrapper redirectOutputToNull() {
220+
this.redirectOutputToNull = true;
221+
return this;
222+
}
223+
224+
public CommandWrapper redirectErrorStream() {
225+
this.redirectErrorStream = true;
226+
return this;
227+
}
228+
229+
public CommandWrapper redirectErrorInherit() {
230+
this.redirectErrorInherit = true;
231+
return this;
232+
}
233+
234+
public CommandWrapper directory(Path directory) {
235+
this.directory = directory;
236+
return this;
237+
}
238+
239+
public ProcessBuilder builder() {
240+
ProcessBuilder builder = new ProcessBuilder(command);
241+
if (redirectOutputToNull) {
242+
builder.redirectOutput(new File(nullFilename));
243+
}
244+
if (directory != null) {
245+
builder.directory(directory.toFile());
246+
}
247+
if (redirectErrorStream) {
248+
builder.redirectErrorStream(true);
249+
}
250+
if (redirectErrorInherit) {
251+
builder.redirectError(ProcessBuilder.Redirect.INHERIT);
252+
}
253+
return builder;
254+
}
255+
256+
public Process start() throws IOException {
257+
return builder().start();
258+
}
259+
260+
public static CommandWrapper cmd() {
261+
CommandWrapper wrapper = new CommandWrapper();
262+
wrapper.prefix.add("cmd");
263+
wrapper.prefix.add("/C");
264+
wrapper.nullFilename = "NUL:";
265+
return wrapper;
266+
}
267+
268+
public static CommandWrapper bash() {
269+
CommandWrapper wrapper = new CommandWrapper();
270+
wrapper.prefix.add("bash");
271+
wrapper.nullFilename = "/dev/null";
272+
return wrapper;
273+
}
274+
}
188275

189276
public LocalGcdHelper(String projectId) {
190277
this.projectId = projectId;
@@ -210,7 +297,7 @@ public void start() throws IOException, InterruptedException {
210297
// If cloud is available we use it, otherwise we download and start gcd
211298
if (INSTALLED_GCD_PATH == null) {
212299
downloadGcd();
213-
gcdExecutablePath = gcdPath.resolve(GCD);
300+
gcdExecutablePath = gcdPath.resolve(GCD_BASENAME);
214301
} else {
215302
gcdExecutablePath = INSTALLED_GCD_PATH;
216303
}
@@ -226,6 +313,7 @@ private void downloadGcd() throws IOException {
226313
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
227314
}
228315
}
316+
229317
// unzip the gcd
230318
try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(gcdZipFile))) {
231319
ZipEntry entry = zipIn.getNextEntry();
@@ -246,38 +334,36 @@ private void startGcd(Path executablePath) throws IOException, InterruptedExcept
246334
// cleanup any possible data for the same project
247335
File datasetFolder = new File(gcdPath.toFile(), projectId);
248336
deleteRecurse(datasetFolder.toPath());
249-
250-
// create the datastore for the project
251-
ProcessBuilder processBuilder = new ProcessBuilder()
252-
.redirectError(ProcessBuilder.Redirect.INHERIT)
253-
.directory(gcdPath.toFile());
337+
338+
// create command wrappers
339+
CommandWrapper gcdCreateCommand;
340+
CommandWrapper gcdStartCommand;
341+
Path gcdAbsolutePath;
254342
if (isWindows()) {
255-
Path gcdAbsolutePath = executablePath.toAbsolutePath().resolve("gcd.cmd");
256-
processBuilder.command("cmd", "/C", gcdAbsolutePath.toString(), "create",
257-
"-p", projectId, projectId);
343+
gcdCreateCommand = CommandWrapper.cmd();
344+
gcdStartCommand = CommandWrapper.cmd();
345+
gcdAbsolutePath = executablePath.toAbsolutePath().resolve("gcd.cmd");
258346
} else {
259-
Path gcdAbsolutePath = executablePath.toAbsolutePath().resolve("gcd.sh");
260-
processBuilder.command("bash", gcdAbsolutePath.toString(), "create",
261-
"-p", projectId, projectId);
347+
gcdCreateCommand = CommandWrapper.bash();
348+
gcdStartCommand = CommandWrapper.bash();
349+
gcdAbsolutePath = executablePath.toAbsolutePath().resolve("gcd.sh");
262350
}
263351

264-
Process temp = processBuilder.start();
352+
// create the datastore for the project
353+
Process temp = gcdCreateCommand.command(gcdAbsolutePath.toString(), "create", "-p", projectId,
354+
projectId)
355+
.redirectErrorInherit()
356+
.directory(gcdPath)
357+
.redirectOutputToNull()
358+
.start();
265359
temp.waitFor();
266360

267361
// start the datastore for the project
268-
processBuilder = new ProcessBuilder()
269-
.directory(gcdPath.toFile())
270-
.redirectErrorStream(true);
271-
if (isWindows()) {
272-
Path gcdAbsolutePath = executablePath.toAbsolutePath().resolve("gcd.cmd");
273-
processBuilder.command("cmd", "/C", gcdAbsolutePath.toString(), "start", "--testing",
274-
"--allow_remote_shutdown", projectId);
275-
} else {
276-
Path gcdAbsolutePath = executablePath.toAbsolutePath().resolve("gcd.sh");
277-
processBuilder.command("bash", gcdAbsolutePath.toString(), "start", "--testing",
278-
"--allow_remote_shutdown", projectId);
279-
}
280-
temp = processBuilder.start();
362+
temp = gcdStartCommand.command(gcdAbsolutePath.toString(), "start", "--testing",
363+
"--allow_remote_shutdown", projectId)
364+
.directory(gcdPath)
365+
.redirectErrorStream()
366+
.start();
281367
processReader = ProcessStreamReader.start(temp, "Dev App Server is now running");
282368
}
283369

0 commit comments

Comments
 (0)