You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by zh...@apache.org on 2017/08/11 17:26:31 UTC

[01/23] geode git commit: GEODE-3313: Test utility supports building jar files with multiple classes [Forced Update!]

Repository: geode
Updated Branches:
  refs/heads/feature/GEODE-3304 e90bd752a -> 4deb189d5 (forced update)


GEODE-3313: Test utility supports building jar files with multiple classes


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/06b839c2
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/06b839c2
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/06b839c2

Branch: refs/heads/feature/GEODE-3304
Commit: 06b839c2b458c47eb26f42de65ca82947b8988c2
Parents: 1efbf58
Author: Jared Stewart <js...@pivotal.io>
Authored: Tue Aug 8 10:11:07 2017 -0700
Committer: Jared Stewart <js...@pivotal.io>
Committed: Thu Aug 10 09:27:39 2017 -0700

----------------------------------------------------------------------
 geode-junit/build.gradle                        |   6 +-
 .../geode/test/compiler/ClassNameExtractor.java |  33 +++++
 .../geode/test/compiler/CompiledSourceCode.java |  35 +++++
 .../apache/geode/test/compiler/JarBuilder.java  | 122 ++++++++++++++++++
 .../geode/test/compiler/JavaCompiler.java       | 123 ++++++++++++++++++
 .../test/compiler/UncompiledSourceCode.java     |  71 +++++++++++
 .../test/compiler/ClassNameExtractorTest.java   |  54 ++++++++
 .../geode/test/compiler/JarBuilderTest.java     | 127 +++++++++++++++++++
 .../geode/test/compiler/JavaCompilerTest.java   |  79 ++++++++++++
 .../test/compiler/UncompiledSourceCodeTest.java |  43 +++++++
 .../geode/test/compiler/AbstractClass.java      |  18 +++
 .../geode/test/compiler/ConcreteClass.java      |  19 +++
 12 files changed, 729 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/build.gradle
----------------------------------------------------------------------
diff --git a/geode-junit/build.gradle b/geode-junit/build.gradle
index e47095f..7c533ad 100755
--- a/geode-junit/build.gradle
+++ b/geode-junit/build.gradle
@@ -19,7 +19,11 @@ dependencies {
   compile 'com.jayway.jsonpath:json-path:' + project.'json-path.version'
   testCompile 'commons-lang:commons-lang:' + project.'commons-lang.version'
   testCompile 'com.google.guava:guava:' + project.'guava.version'
-  testCompile 'org.assertj:assertj-core:' + project.'assertj-core.version'
+  compile 'org.assertj:assertj-core:' + project.'assertj-core.version'
+  compile 'commons-io:commons-io:' + project.'commons-io.version'
+  compile 'commons-lang:commons-lang:' + project.'commons-lang.version'
+  compile 'com.google.guava:guava:' + project.'guava.version'
+
 
   compile('junit:junit:' + project.'junit.version') {
     exclude module: 'hamcrest-core'

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java
new file mode 100644
index 0000000..c48224c
--- /dev/null
+++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/ClassNameExtractor.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ClassNameExtractor {
+  private static final Pattern EXTRACT_CLASS_NAME_REGEX =
+      Pattern.compile("(?:public|private|protected)* *(?:abstract)* *(?:class|interface) +(\\w+)");
+
+  public String extractFromSourceCode(String sourceCode) {
+    Matcher m = EXTRACT_CLASS_NAME_REGEX.matcher(sourceCode);
+    if (m.find()) {
+      return m.group(1);
+    } else {
+      throw new IllegalArgumentException(
+          String.format("Unable to parse class or interface name from: \n'%s'", sourceCode));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java
new file mode 100644
index 0000000..c1bfa3d
--- /dev/null
+++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/CompiledSourceCode.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+public class CompiledSourceCode {
+
+  /**
+   * Fully qualified classname in a format suitable for Class.forName
+   */
+  public String className;
+
+  public byte[] compiledBytecode;
+
+  public CompiledSourceCode(String className, byte[] aBytes) {
+    this.className = className.replace('/', '.');
+    this.compiledBytecode = aBytes;
+  }
+
+  @Override
+  public String toString() {
+    return className;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java
new file mode 100644
index 0000000..beea476
--- /dev/null
+++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/JarBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+
+import org.assertj.core.api.Assertions;
+
+
+/**
+ * This class accepts java source code in the format of .java source files or strings containing the
+ * contents of .java source files, and compiles the given source code into a jar file specified by
+ * the user.
+ *
+ * <p>
+ * Example of usage:
+ *
+ * <pre>
+ *  &#064;Rule
+ *  public TemporaryFolder temporaryFolder= new TemporaryFolder();
+ *
+ *  &#064;Test
+ *  public void buildJarUsingStrings() {
+ *  File tempDir = temporaryFolder.getRoot()
+ *  JarBuilder jarBuilder = new JarBuilder(tempDir);
+ *  File outputJar = new File("output.jar");
+ *
+ *  String classInFooBarPackage = &quot;package foo.bar; public class ClassA {int n = 10;}&quot;;
+ *  String classInDefaultPackage = &quot;public class ClassB {}&quot;;
+ *  jarBuilder.buildJar(outputJar, classInFooBarPackage, classInDefaultPackage);
+ *     }
+ *
+ *  &#064;Test
+ *  public void buildJarUsingFiles() {
+ *  File tempDir = temporaryFolder.getRoot()
+ *  JarBuilder jarBuilder = new JarBuilder(tempDir);
+ *  File outputJar = new File("output.jar");
+ *
+ *  File sourceFileOne = new File("ClassA.java");
+ *  File sourceFileTwo = new File("ClassB.java");
+ *  jarBuilder.buildJar(outputJar, sourceFileOne, sourceFileTwo);
+ *     }
+ *
+ *  &#064;Test
+ *  public void buildJarUsingClassNames() {
+ *  File tempDir = temporaryFolder.getRoot()
+ *  JarBuilder jarBuilder = new JarBuilder(tempDir);
+ *  File outputJar = new File("output.jar");
+ *
+ *  String classInFooBarPackage = "foo.bar.ClassInFooBarPackage";
+ *  String classInDefaultPackage = "ClassInDefaultPackage";
+ *  jarBuilder.buildJar(outputJar, classInFooBarPackage, classInDefaultPackage);
+ *     }
+ * </pre>
+ **/
+public class JarBuilder {
+  private final JavaCompiler javaCompiler = new JavaCompiler();
+
+  public void buildJarFromClassNames(File outputJarFile, String... classNames) throws IOException {
+    UncompiledSourceCode[] uncompiledSourceCodes = Arrays.stream(classNames)
+        .map(UncompiledSourceCode::fromClassName).toArray(UncompiledSourceCode[]::new);
+
+    List<CompiledSourceCode> compiledSourceCodes = javaCompiler.compile(uncompiledSourceCodes);
+
+    buildJar(outputJarFile, compiledSourceCodes);
+  }
+
+  public void buildJar(File outputJarFile, String... sourceFileContents) throws IOException {
+    List<CompiledSourceCode> compiledSourceCodes = javaCompiler.compile(sourceFileContents);
+
+    buildJar(outputJarFile, compiledSourceCodes);
+  }
+
+  public void buildJar(File outputJarFile, File... sourceFiles) throws IOException {
+    List<CompiledSourceCode> compiledSourceCodes = javaCompiler.compile(sourceFiles);
+
+    buildJar(outputJarFile, compiledSourceCodes);
+  }
+
+  private void buildJar(File outputJarFile, List<CompiledSourceCode> compiledSourceCodes)
+      throws IOException {
+    assertThat(outputJarFile).doesNotExist();
+
+    try (FileOutputStream outputStream = new FileOutputStream(outputJarFile)) {
+      JarOutputStream jarOutputStream = new JarOutputStream(outputStream);
+      for (CompiledSourceCode compiledSource : compiledSourceCodes) {
+
+        String formattedName = compiledSource.className.replace(".", "/");
+        if (!formattedName.endsWith(".class")) {
+          formattedName = formattedName.concat(".class");
+        }
+
+        JarEntry entry = new JarEntry(formattedName);
+        entry.setTime(System.currentTimeMillis());
+        jarOutputStream.putNextEntry(entry);
+        jarOutputStream.write(compiledSource.compiledBytecode);
+        jarOutputStream.closeEntry();
+      }
+      jarOutputStream.close();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java
new file mode 100644
index 0000000..8449605
--- /dev/null
+++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/JavaCompiler.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import static java.util.stream.Collectors.toList;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.tools.ToolProvider;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+import org.apache.commons.io.FileUtils;
+
+
+public class JavaCompiler {
+  private File tempDir;
+
+  public JavaCompiler() {
+    this.tempDir = Files.createTempDir();
+    tempDir.deleteOnExit();
+  }
+
+  public List<CompiledSourceCode> compile(File... sourceFiles) throws IOException {
+    String[] sourceFileContents =
+        Arrays.stream(sourceFiles).map(this::readFileToString).toArray(String[]::new);
+
+    return compile(sourceFileContents);
+  }
+
+  public List<CompiledSourceCode> compile(String... sourceFileContents) throws IOException {
+    UncompiledSourceCode[] uncompiledSourceCodes = Arrays.stream(sourceFileContents)
+        .map(UncompiledSourceCode::fromSourceCode).toArray(UncompiledSourceCode[]::new);
+
+    return compile(uncompiledSourceCodes);
+  }
+
+  public List<CompiledSourceCode> compile(UncompiledSourceCode... uncompiledSources)
+      throws IOException {
+    File temporarySourcesDirectory = createSubdirectory(tempDir, "sources");
+    File temporaryClassesDirectory = createSubdirectory(tempDir, "classes");
+
+    List<String> options = Stream.of("-d", temporaryClassesDirectory.getAbsolutePath(),
+        "-classpath", System.getProperty("java.class.path")).collect(toList());
+
+    try {
+      for (UncompiledSourceCode sourceCode : uncompiledSources) {
+        File sourceFile = new File(temporarySourcesDirectory, sourceCode.simpleClassName + ".java");
+        FileUtils.writeStringToFile(sourceFile, sourceCode.sourceCode, Charsets.UTF_8);
+        options.add(sourceFile.getAbsolutePath());
+      }
+
+      int exitCode = ToolProvider.getSystemJavaCompiler().run(System.in, System.out, System.err,
+          options.toArray(new String[] {}));
+
+      if (exitCode != 0) {
+        throw new RuntimeException(
+            "Unable to compile the given source code. See System.err for details.");
+      }
+
+      List<CompiledSourceCode> compiledSourceCodes = new ArrayList<>();
+      addCompiledClasses(compiledSourceCodes, "", temporaryClassesDirectory);
+      return compiledSourceCodes;
+    } finally {
+      FileUtils.deleteDirectory(temporaryClassesDirectory);
+    }
+  }
+
+  private static void addCompiledClasses(List<CompiledSourceCode> ret, String pkgName, File dir)
+      throws IOException {
+    for (File file : dir.listFiles()) {
+      String filename = file.getName();
+
+      if (file.isDirectory()) {
+        String qname = pkgName + filename + ".";
+        addCompiledClasses(ret, qname, file);
+      } else if (filename.endsWith(".class")) {
+        String qname = pkgName + filename.substring(0, filename.length() - 6);
+        ret.add(new CompiledSourceCode(qname, FileUtils.readFileToByteArray(file)));
+      } else {
+        System.err.println("Unexpected file : " + file.getAbsolutePath());
+      }
+    }
+  }
+
+  private File createSubdirectory(File parent, String directoryName) {
+    File subdirectory = parent.toPath().resolve(directoryName).toFile();
+    if (!subdirectory.exists()) {
+      subdirectory.mkdirs();
+    }
+
+    if (!subdirectory.exists() || !subdirectory.isDirectory()) {
+      throw new IllegalArgumentException("Invalid directory" + subdirectory.getAbsolutePath());
+    }
+
+    return subdirectory;
+  }
+
+  private String readFileToString(File file) {
+    try {
+      return FileUtils.readFileToString(file, Charsets.UTF_8);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java b/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java
new file mode 100644
index 0000000..4161f5e
--- /dev/null
+++ b/geode-junit/src/main/java/org/apache/geode/test/compiler/UncompiledSourceCode.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.SystemUtils;
+
+public class UncompiledSourceCode {
+  public String simpleClassName;
+  public String sourceCode;
+
+  private UncompiledSourceCode(String simpleClassName, String sourceCode) {
+    this.simpleClassName = simpleClassName;
+    this.sourceCode = sourceCode;
+  }
+
+  public static UncompiledSourceCode fromSourceCode(String sourceCode) {
+    String simpleClassName = new ClassNameExtractor().extractFromSourceCode(sourceCode);
+    return new UncompiledSourceCode(simpleClassName, sourceCode);
+  }
+
+  public static UncompiledSourceCode fromClassName(String fullyQualifiedClassName) {
+    ClassNameWithPackage classNameWithPackage = ClassNameWithPackage.of(fullyQualifiedClassName);
+    boolean isPackageSpecified = StringUtils.isNotBlank(classNameWithPackage.packageName);
+
+    StringBuilder sourceCode = new StringBuilder();
+    if (isPackageSpecified) {
+      sourceCode.append(String.format("package %s;", classNameWithPackage.packageName));
+      sourceCode.append(SystemUtils.LINE_SEPARATOR);
+    }
+
+    sourceCode.append(String.format("public class %s {}", classNameWithPackage.simpleClassName));
+
+    return new UncompiledSourceCode(classNameWithPackage.simpleClassName, sourceCode.toString());
+  }
+
+  private static class ClassNameWithPackage {
+    String packageName;
+    String simpleClassName;
+
+    static ClassNameWithPackage of(String fqClassName) {
+      int indexOfLastDot = fqClassName.lastIndexOf(".");
+
+      if (indexOfLastDot == -1) {
+        return new ClassNameWithPackage("", fqClassName);
+      } else {
+        String specifiedPackage = fqClassName.substring(0, indexOfLastDot);
+        String simpleClassName = fqClassName.substring(indexOfLastDot + 1);
+
+        return new ClassNameWithPackage(specifiedPackage, simpleClassName);
+      }
+    }
+
+    private ClassNameWithPackage(String packageName, String simpleClassName) {
+      this.packageName = packageName;
+      this.simpleClassName = simpleClassName;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java
new file mode 100644
index 0000000..db060f8
--- /dev/null
+++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/ClassNameExtractorTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class ClassNameExtractorTest {
+  private static final String SPACE = " ";
+  private static final String CLASS_NAME_TO_FIND = "MyClassNameToFind";
+
+  @Test
+  public void extractsClassNames() throws Exception {
+    SoftAssertions softAssertions = new SoftAssertions();
+    ClassNameExtractor classNameExtractor = new ClassNameExtractor();
+
+    Set<List<String>> permutationsToTest = Sets.cartesianProduct(
+        ImmutableSet.of("public ", "private ", "protected ", ""), ImmutableSet.of("abstract ", ""),
+        ImmutableSet.of("static ", ""), ImmutableSet.of("class ", "interface "),
+        ImmutableSet.of("extends Foo ", ""), ImmutableSet.of("implements Bar ", ""));
+
+    for (List<String> permutation : permutationsToTest) {
+      String firstLineOfSource =
+          permutation.get(0) + permutation.get(1) + permutation.get(2) + permutation.get(3)
+              + CLASS_NAME_TO_FIND + SPACE + permutation.get(4) + permutation.get(5) + " {";
+
+      String className = classNameExtractor.extractFromSourceCode(firstLineOfSource);
+      softAssertions.assertThat(className).isEqualTo(CLASS_NAME_TO_FIND);
+    }
+
+    softAssertions.assertAll();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java
new file mode 100644
index 0000000..58adc02
--- /dev/null
+++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/JarBuilderTest.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import static java.util.stream.Collectors.toSet;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class JarBuilderTest {
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  private JarBuilder jarBuilder;
+  private File outputJar;
+
+  @Before
+  public void setup() {
+    jarBuilder = new JarBuilder();
+    outputJar = new File(temporaryFolder.getRoot(), "output.jar");
+  }
+
+  @Test
+  public void jarWithSingleClass() throws Exception {
+    File classContents = loadTestResource("AbstractClass.java");
+    jarBuilder.buildJar(outputJar, classContents);
+
+    Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar);
+    assertThat(jarEntryNames)
+        .containsExactlyInAnyOrder("org/apache/geode/test/compiler/AbstractClass.class");
+  }
+
+  @Test
+  public void jarWithTwoDependentClasses() throws Exception {
+    File sourceFileOne = loadTestResource("AbstractClass.java");
+    File sourceFileTwo = loadTestResource("ConcreteClass.java");
+
+    jarBuilder.buildJar(outputJar, sourceFileOne, sourceFileTwo);
+
+    Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar);
+
+    assertThat(jarEntryNames).containsExactlyInAnyOrder(
+        "org/apache/geode/test/compiler/AbstractClass.class",
+        "org/apache/geode/test/compiler/ConcreteClass.class");
+  }
+
+  @Test
+  public void jarWithClassInDefaultPackage() throws Exception {
+    String classInFooBarPackage = "package foo.bar; public class ClassInFooBarPackage {}";
+    String classInDefaultPackage = "public class ClassInDefaultPackage {}";
+    jarBuilder.buildJar(outputJar, classInFooBarPackage, classInDefaultPackage);
+
+    Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar);
+    assertThat(jarEntryNames).containsExactlyInAnyOrder("ClassInDefaultPackage.class",
+        "foo/bar/ClassInFooBarPackage.class");
+  }
+
+
+  @Test
+  public void jarFromOnlyClassNames() throws Exception {
+    String defaultPackageClassName = "DefaultClass";
+    String otherPackageClassName = "foo.bar.OtherClass";
+    jarBuilder.buildJarFromClassNames(outputJar, defaultPackageClassName, otherPackageClassName);
+
+    Set<String> jarEntryNames = jarEntryNamesFromFile(outputJar);
+    assertThat(jarEntryNames).containsExactlyInAnyOrder("DefaultClass.class",
+        "foo/bar/OtherClass.class");
+  }
+
+  @Test
+  public void canLoadClassesFromJar() throws Exception {
+    String defaultPackageClassName = "DefaultClass";
+    String otherPackageClassName = "foo.bar.OtherClass";
+    jarBuilder.buildJarFromClassNames(outputJar, defaultPackageClassName, otherPackageClassName);
+
+    URLClassLoader jarClassLoader = new URLClassLoader(new URL[] {outputJar.toURL()});
+
+    jarClassLoader.loadClass("DefaultClass");
+    jarClassLoader.loadClass("foo.bar.OtherClass");
+  }
+
+  private Set<String> jarEntryNamesFromFile(File jarFile) throws Exception {
+    assertThat(jarFile).exists();
+
+    Enumeration<JarEntry> jarEntries = new JarFile(jarFile).entries();
+    return Collections.list(jarEntries).stream().map(JarEntry::getName).collect(toSet());
+  }
+
+  private File loadTestResource(String fileName) throws URISyntaxException {
+    URL resourceFileURL = this.getClass().getResource(fileName);
+    assertThat(resourceFileURL).isNotNull();
+
+    URI resourceUri = resourceFileURL.toURI();
+    return new File(resourceUri);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java
new file mode 100644
index 0000000..425169d
--- /dev/null
+++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/JavaCompilerTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.assertj.core.api.Assertions;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class JavaCompilerTest {
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Test
+  public void compileSingleClass() throws Exception {
+    File implementsFunctionSourceFile = getFileFromTestResources("AbstractClass.java");
+    String classContents = FileUtils.readFileToString(implementsFunctionSourceFile, "UTF-8");
+
+    List<CompiledSourceCode> compiledSourceCodes = new JavaCompiler().compile(classContents);
+
+    assertThat(compiledSourceCodes).hasSize(1);
+  }
+
+  @Test
+  public void compileTwoDependentClasses() throws Exception {
+    File sourceFileOne = getFileFromTestResources("AbstractClass.java");
+    File sourceFileTwo = getFileFromTestResources("ConcreteClass.java");
+
+    List<CompiledSourceCode> compiledSourceCodes =
+        new JavaCompiler().compile(sourceFileOne, sourceFileTwo);
+
+    assertThat(compiledSourceCodes).hasSize(2);
+  }
+
+  @Test
+  public void invalidSourceThrowsException() throws Exception {
+    JavaCompiler javaCompiler = new JavaCompiler();
+    String sourceCode = "public class foo {this is not valid java source code}";
+    assertThatThrownBy(() -> javaCompiler.compile(sourceCode)).isInstanceOf(Exception.class);
+  }
+
+  private File getFileFromTestResources(String fileName) throws URISyntaxException {
+    URL resourceFileURL = this.getClass().getResource(fileName);
+    assertThat(resourceFileURL).isNotNull();
+
+    URI resourceUri = resourceFileURL.toURI();
+    File file = new File(resourceUri);
+
+    assertThat(file).exists();
+    return file;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java b/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java
new file mode 100644
index 0000000..3db8a72
--- /dev/null
+++ b/geode-junit/src/test/java/org/apache/geode/test/compiler/UncompiledSourceCodeTest.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.apache.commons.lang.SystemUtils;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class UncompiledSourceCodeTest {
+  @Test
+  public void fromClassNameWithNoPackage() throws Exception {
+    UncompiledSourceCode uncompiledSourceCode = UncompiledSourceCode.fromClassName("NoPackage");
+    assertThat(uncompiledSourceCode.simpleClassName).isEqualTo("NoPackage");
+    assertThat(uncompiledSourceCode.sourceCode).isEqualTo("public class NoPackage {}");
+  }
+
+  @Test
+  public void fromClassNameWithPackage() throws Exception {
+    UncompiledSourceCode uncompiledSourceCode =
+        UncompiledSourceCode.fromClassName("foo.bar.ClassName");
+    assertThat(uncompiledSourceCode.simpleClassName).isEqualTo("ClassName");
+    assertThat(uncompiledSourceCode.sourceCode)
+        .isEqualTo("package foo.bar;" + SystemUtils.LINE_SEPARATOR + "public class ClassName {}");
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java b/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java
new file mode 100644
index 0000000..24ed0c6
--- /dev/null
+++ b/geode-junit/src/test/resources/org/apache/geode/test/compiler/AbstractClass.java
@@ -0,0 +1,18 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+public abstract class AbstractClass {
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/06b839c2/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java
----------------------------------------------------------------------
diff --git a/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java b/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java
new file mode 100644
index 0000000..bf98672
--- /dev/null
+++ b/geode-junit/src/test/resources/org/apache/geode/test/compiler/ConcreteClass.java
@@ -0,0 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.test.compiler;
+
+
+public class ConcreteClass extends AbstractClass {
+}


[07/23] geode git commit: GEODE-3328: refactor ConnectCommand

Posted by zh...@apache.org.
GEODE-3328: refactor ConnectCommand

* connect command will prompt for missing ssl configs if ssl is indicated by any options
* command ssl options will override the properties loaded in the file
* reworked connect with ssl so that the configuration won't get cached accidentally.
* have auto connect also prompt for missing ssl configs, not in the socket creator
* change the properties file type in the start server and start locator command to be File instead of String


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/7352fcc7
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/7352fcc7
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/7352fcc7

Branch: refs/heads/feature/GEODE-3304
Commit: 7352fcc7e485984b57d72373b468440d09556b5a
Parents: 1bd15f8
Author: Jinmei Liao <ji...@pivotal.io>
Authored: Sat Jul 29 21:32:50 2017 -0700
Committer: Jinmei Liao <ji...@pivotal.io>
Committed: Thu Aug 10 13:50:31 2017 -0700

----------------------------------------------------------------------
 .../distributed/ConfigurationProperties.java    |   4 +
 .../internal/tcpserver/TcpClient.java           |  12 +-
 .../internal/net/SSLConfigurationFactory.java   | 202 ++++----
 .../internal/JmxManagerLocatorRequest.java      |  47 +-
 .../internal/beans/BeanUtilFuncs.java           |   1 +
 .../cli/AbstractCliAroundInterceptor.java       |  18 +-
 .../internal/cli/commands/ConnectCommand.java   | 482 ++++++++-----------
 .../internal/cli/commands/ShellCommands.java    |  77 ++-
 .../cli/commands/StartLocatorCommand.java       | 148 ++----
 .../internal/cli/commands/StartMemberUtils.java |  13 +-
 .../cli/commands/StartServerCommand.java        |  34 +-
 .../cli/commands/UserInputProperty.java         | 120 +++++
 .../internal/cli/i18n/CliStrings.java           |   4 +-
 .../management/internal/cli/shell/Gfsh.java     |  20 +-
 .../internal/cli/shell/JmxOperationInvoker.java | 147 ++----
 .../internal/cli/util/GfshConsoleReader.java    |  16 +-
 .../ClusterConfigurationStatusRetriever.java    |  17 +-
 .../net/SSLConfigurationFactoryJUnitTest.java   |  37 +-
 .../ConnectToLocatorSSLDUnitTest.java           | 104 ----
 .../ConnectToLocatorWithLegacySSLDUnitTest.java | 118 -----
 .../internal/cli/GfshParserConverterTest.java   |  25 +-
 .../cli/commands/ConnectCommandTest.java        | 300 ++++++++++++
 .../cli/commands/GfshCommandJUnitTest.java      |  41 +-
 .../cli/commands/UserInputPropertyTest.java     | 102 ++++
 .../CacheServerManagementDUnitTest.java         |  58 ++-
 .../commands/ConnectCommandIntegrationTest.java |  50 ++
 .../cli/commands/ConnectCommandWithSSLTest.java | 303 ++++++++++++
 .../ConnectCommandWithSecurityTest.java         |  55 +++
 .../ConnectToLocatorSSLOverHttpTest.java        |  43 --
 29 files changed, 1551 insertions(+), 1047 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
index 91a6443..aae7d8a 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java
@@ -687,6 +687,10 @@ public interface ConfigurationProperties {
    */
   String SSL_WEB_ALIAS = "ssl-web-alias";
 
+
+  @Deprecated
+  String HTTP_SERVICE_SSL_PREFIX = "http-service-ssl-";
+
   /**
    * The static String definition of the <i>"http-service-ssl-ciphers"</i> property <a
    * name="http-service-ssl-ciphers"/a>

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java
index d406891..933b25d 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java
@@ -24,9 +24,9 @@ import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Properties;
 
 import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
 
 import org.apache.logging.log4j.Logger;
 
@@ -36,7 +36,9 @@ import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.internal.Version;
 import org.apache.geode.internal.VersionedDataInputStream;
 import org.apache.geode.internal.VersionedDataOutputStream;
+import org.apache.geode.internal.admin.SSLConfig;
 import org.apache.geode.internal.logging.LogService;
+import org.apache.geode.internal.net.SSLConfigurationFactory;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.net.SocketCreatorFactory;
 import org.apache.geode.internal.security.SecurableCommunicationChannel;
@@ -72,6 +74,12 @@ public class TcpClient {
     this(SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.LOCATOR));
   }
 
+  public TcpClient(Properties properties) {
+    SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(properties,
+        SecurableCommunicationChannel.LOCATOR);
+    this.socketCreator = new SocketCreator(sslConfig);
+  }
+
   /**
    * Constructs a new TcpClient
    * 
@@ -310,7 +318,7 @@ public class TcpClient {
         Object readObject = DataSerializer.readObject(in);
         if (!(readObject instanceof VersionResponse)) {
           throw new LocatorCancelException(
-              "Unrecognisable response received: object is null. This could be the result of trying to connect a non-SSL-enabled locator to an SSL-enabled locator.");
+              "Unrecognisable response received: This could be the result of trying to connect a non-SSL-enabled client to an SSL-enabled locator.");
         }
         VersionResponse response = (VersionResponse) readObject;
         if (response != null) {

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java b/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java
index 4b98617..00ccb74 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java
@@ -24,6 +24,7 @@ import org.apache.commons.lang.StringUtils;
 
 import org.apache.geode.GemFireConfigException;
 import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.DistributionConfigImpl;
 import org.apache.geode.internal.admin.SSLConfig;
 import org.apache.geode.internal.security.SecurableCommunicationChannel;
 
@@ -63,6 +64,11 @@ public class SSLConfigurationFactory {
     getInstance().distributionConfig = distributionConfig;
   }
 
+  /**
+   * @deprecated since GEODE 1.3, use #{getSSLConfigForComponent({@link DistributionConfig} ,
+   *             {@link SecurableCommunicationChannel})} instead
+   */
+  @Deprecated
   public static SSLConfig getSSLConfigForComponent(
       SecurableCommunicationChannel sslEnabledComponent) {
     SSLConfig sslConfig = getInstance().getRegisteredSSLConfigForComponent(sslEnabledComponent);
@@ -80,64 +86,68 @@ public class SSLConfigurationFactory {
 
   private SSLConfig createSSLConfigForComponent(
       final SecurableCommunicationChannel sslEnabledComponent) {
-    SSLConfig sslConfig = createSSLConfig(sslEnabledComponent);
+    return createSSLConfigForComponent(getDistributionConfig(), sslEnabledComponent);
+  }
+
+  private SSLConfig createSSLConfigForComponent(final DistributionConfig distributionConfig,
+      final SecurableCommunicationChannel sslEnabledComponent) {
+    SSLConfig sslConfig = createSSLConfig(distributionConfig, sslEnabledComponent);
     SecurableCommunicationChannel[] sslEnabledComponents =
-        getDistributionConfig().getSecurableCommunicationChannels();
+        distributionConfig.getSecurableCommunicationChannels();
     if (sslEnabledComponents.length == 0) {
-      sslConfig = configureLegacyClusterSSL(sslConfig);
+      sslConfig = configureLegacyClusterSSL(distributionConfig, sslConfig);
     }
     sslConfig.setSecurableCommunicationChannel(sslEnabledComponent);
     switch (sslEnabledComponent) {
       case ALL: {
         // Create a SSLConfig separate for HTTP Service. As the require-authentication might differ
-        createSSLConfigForComponent(SecurableCommunicationChannel.WEB);
+        createSSLConfigForComponent(distributionConfig, SecurableCommunicationChannel.WEB);
         break;
       }
       case CLUSTER: {
         if (sslEnabledComponents.length > 0) {
-          sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getClusterSSLAlias());
+          sslConfig = setAliasForComponent(sslConfig, distributionConfig.getClusterSSLAlias());
         } else {
-          sslConfig = configureLegacyClusterSSL(sslConfig);
+          sslConfig = configureLegacyClusterSSL(distributionConfig, sslConfig);
         }
         break;
       }
       case LOCATOR: {
         if (sslEnabledComponents.length > 0) {
-          sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getLocatorSSLAlias());
+          sslConfig = setAliasForComponent(sslConfig, distributionConfig.getLocatorSSLAlias());
         }
         break;
       }
       case SERVER: {
         if (sslEnabledComponents.length > 0) {
-          sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getServerSSLAlias());
+          sslConfig = setAliasForComponent(sslConfig, distributionConfig.getServerSSLAlias());
         } else {
-          sslConfig = configureLegacyServerSSL(sslConfig);
+          sslConfig = configureLegacyServerSSL(distributionConfig, sslConfig);
         }
         break;
       }
       case GATEWAY: {
         if (sslEnabledComponents.length > 0) {
-          sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getGatewaySSLAlias());
+          sslConfig = setAliasForComponent(sslConfig, distributionConfig.getGatewaySSLAlias());
         } else {
-          sslConfig = configureLegacyGatewaySSL(sslConfig);
+          sslConfig = configureLegacyGatewaySSL(distributionConfig, sslConfig);
         }
         break;
       }
       case WEB: {
         if (sslEnabledComponents.length > 0) {
-          sslConfig =
-              setAliasForComponent(sslConfig, getDistributionConfig().getHTTPServiceSSLAlias());
-          sslConfig.setRequireAuth(getDistributionConfig().getSSLWebRequireAuthentication());
+          sslConfig = setAliasForComponent(sslConfig, distributionConfig.getHTTPServiceSSLAlias());
+          sslConfig.setRequireAuth(distributionConfig.getSSLWebRequireAuthentication());
         } else {
-          sslConfig = configureLegacyHttpServiceSSL(sslConfig);
+          sslConfig = configureLegacyHttpServiceSSL(distributionConfig, sslConfig);
         }
         break;
       }
       case JMX: {
         if (sslEnabledComponents.length > 0) {
-          sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getJMXSSLAlias());
+          sslConfig = setAliasForComponent(sslConfig, distributionConfig.getJMXSSLAlias());
         } else {
-          sslConfig = configureLegacyJMXSSL(sslConfig);
+          sslConfig = configureLegacyJMXSSL(distributionConfig, sslConfig);
         }
         break;
       }
@@ -153,33 +163,35 @@ public class SSLConfigurationFactory {
     return sslConfig;
   }
 
-  private SSLConfig createSSLConfig(final SecurableCommunicationChannel sslEnabledComponent) {
+  private SSLConfig createSSLConfig(final DistributionConfig distributionConfig,
+      final SecurableCommunicationChannel sslEnabledComponent) {
     SSLConfig sslConfig = new SSLConfig();
-    sslConfig.setCiphers(getDistributionConfig().getSSLCiphers());
-    sslConfig.setEnabled(determineIfSSLEnabledForSSLComponent(sslEnabledComponent));
-    sslConfig.setKeystore(getDistributionConfig().getSSLKeyStore());
-    sslConfig.setKeystorePassword(getDistributionConfig().getSSLKeyStorePassword());
-    sslConfig.setKeystoreType(getDistributionConfig().getSSLKeyStoreType());
-    sslConfig.setTruststore(getDistributionConfig().getSSLTrustStore());
-    sslConfig.setTruststorePassword(getDistributionConfig().getSSLTrustStorePassword());
-    sslConfig.setTruststoreType(getDistributionConfig().getSSLTrustStoreType());
-    sslConfig.setProtocols(getDistributionConfig().getSSLProtocols());
-    sslConfig.setRequireAuth(getDistributionConfig().getSSLRequireAuthentication());
-    sslConfig.setAlias(getDistributionConfig().getSSLDefaultAlias());
+    sslConfig.setCiphers(distributionConfig.getSSLCiphers());
+    sslConfig
+        .setEnabled(determineIfSSLEnabledForSSLComponent(distributionConfig, sslEnabledComponent));
+    sslConfig.setKeystore(distributionConfig.getSSLKeyStore());
+    sslConfig.setKeystorePassword(distributionConfig.getSSLKeyStorePassword());
+    sslConfig.setKeystoreType(distributionConfig.getSSLKeyStoreType());
+    sslConfig.setTruststore(distributionConfig.getSSLTrustStore());
+    sslConfig.setTruststorePassword(distributionConfig.getSSLTrustStorePassword());
+    sslConfig.setTruststoreType(distributionConfig.getSSLTrustStoreType());
+    sslConfig.setProtocols(distributionConfig.getSSLProtocols());
+    sslConfig.setRequireAuth(distributionConfig.getSSLRequireAuthentication());
+    sslConfig.setAlias(distributionConfig.getSSLDefaultAlias());
     return sslConfig;
   }
 
-  private boolean determineIfSSLEnabledForSSLComponent(
+  private boolean determineIfSSLEnabledForSSLComponent(final DistributionConfig distributionConfig,
       final SecurableCommunicationChannel sslEnabledComponent) {
-    if (ArrayUtils.contains(getDistributionConfig().getSecurableCommunicationChannels(),
+    if (ArrayUtils.contains(distributionConfig.getSecurableCommunicationChannels(),
         SecurableCommunicationChannel.NONE)) {
       return false;
     }
-    if (ArrayUtils.contains(getDistributionConfig().getSecurableCommunicationChannels(),
+    if (ArrayUtils.contains(distributionConfig.getSecurableCommunicationChannels(),
         SecurableCommunicationChannel.ALL)) {
       return true;
     }
-    return ArrayUtils.contains(getDistributionConfig().getSecurableCommunicationChannels(),
+    return ArrayUtils.contains(distributionConfig.getSecurableCommunicationChannels(),
         sslEnabledComponent) ? true : false;
   }
 
@@ -189,17 +201,18 @@ public class SSLConfigurationFactory {
    * @return A sslConfig object describing the ssl config for the server component
    * @deprecated as of Geode 1.0
    */
-  private SSLConfig configureLegacyClusterSSL(SSLConfig sslConfig) {
-    sslConfig.setCiphers(getDistributionConfig().getClusterSSLCiphers());
-    sslConfig.setEnabled(getDistributionConfig().getClusterSSLEnabled());
-    sslConfig.setKeystore(getDistributionConfig().getClusterSSLKeyStore());
-    sslConfig.setKeystorePassword(getDistributionConfig().getClusterSSLKeyStorePassword());
-    sslConfig.setKeystoreType(getDistributionConfig().getClusterSSLKeyStoreType());
-    sslConfig.setTruststore(getDistributionConfig().getClusterSSLTrustStore());
-    sslConfig.setTruststorePassword(getDistributionConfig().getClusterSSLTrustStorePassword());
-    sslConfig.setTruststoreType(getDistributionConfig().getClusterSSLKeyStoreType());
-    sslConfig.setProtocols(getDistributionConfig().getClusterSSLProtocols());
-    sslConfig.setRequireAuth(getDistributionConfig().getClusterSSLRequireAuthentication());
+  private SSLConfig configureLegacyClusterSSL(final DistributionConfig distributionConfig,
+      final SSLConfig sslConfig) {
+    sslConfig.setCiphers(distributionConfig.getClusterSSLCiphers());
+    sslConfig.setEnabled(distributionConfig.getClusterSSLEnabled());
+    sslConfig.setKeystore(distributionConfig.getClusterSSLKeyStore());
+    sslConfig.setKeystorePassword(distributionConfig.getClusterSSLKeyStorePassword());
+    sslConfig.setKeystoreType(distributionConfig.getClusterSSLKeyStoreType());
+    sslConfig.setTruststore(distributionConfig.getClusterSSLTrustStore());
+    sslConfig.setTruststorePassword(distributionConfig.getClusterSSLTrustStorePassword());
+    sslConfig.setTruststoreType(distributionConfig.getClusterSSLKeyStoreType());
+    sslConfig.setProtocols(distributionConfig.getClusterSSLProtocols());
+    sslConfig.setRequireAuth(distributionConfig.getClusterSSLRequireAuthentication());
     return sslConfig;
   }
 
@@ -209,17 +222,18 @@ public class SSLConfigurationFactory {
    * @return A sslConfig object describing the ssl config for the server component
    * @deprecated as of Geode 1.0
    */
-  private SSLConfig configureLegacyServerSSL(SSLConfig sslConfig) {
-    sslConfig.setCiphers(getDistributionConfig().getServerSSLCiphers());
-    sslConfig.setEnabled(getDistributionConfig().getServerSSLEnabled());
-    sslConfig.setKeystore(getDistributionConfig().getServerSSLKeyStore());
-    sslConfig.setKeystorePassword(getDistributionConfig().getServerSSLKeyStorePassword());
-    sslConfig.setKeystoreType(getDistributionConfig().getServerSSLKeyStoreType());
-    sslConfig.setTruststore(getDistributionConfig().getServerSSLTrustStore());
-    sslConfig.setTruststorePassword(getDistributionConfig().getServerSSLTrustStorePassword());
-    sslConfig.setTruststoreType(getDistributionConfig().getServerSSLKeyStoreType());
-    sslConfig.setProtocols(getDistributionConfig().getServerSSLProtocols());
-    sslConfig.setRequireAuth(getDistributionConfig().getServerSSLRequireAuthentication());
+  private SSLConfig configureLegacyServerSSL(final DistributionConfig distributionConfig,
+      final SSLConfig sslConfig) {
+    sslConfig.setCiphers(distributionConfig.getServerSSLCiphers());
+    sslConfig.setEnabled(distributionConfig.getServerSSLEnabled());
+    sslConfig.setKeystore(distributionConfig.getServerSSLKeyStore());
+    sslConfig.setKeystorePassword(distributionConfig.getServerSSLKeyStorePassword());
+    sslConfig.setKeystoreType(distributionConfig.getServerSSLKeyStoreType());
+    sslConfig.setTruststore(distributionConfig.getServerSSLTrustStore());
+    sslConfig.setTruststorePassword(distributionConfig.getServerSSLTrustStorePassword());
+    sslConfig.setTruststoreType(distributionConfig.getServerSSLKeyStoreType());
+    sslConfig.setProtocols(distributionConfig.getServerSSLProtocols());
+    sslConfig.setRequireAuth(distributionConfig.getServerSSLRequireAuthentication());
     return sslConfig;
   }
 
@@ -229,17 +243,18 @@ public class SSLConfigurationFactory {
    * @return A sslConfig object describing the ssl config for the jmx component
    * @deprecated as of Geode 1.0
    */
-  private SSLConfig configureLegacyJMXSSL(SSLConfig sslConfig) {
-    sslConfig.setCiphers(getDistributionConfig().getJmxManagerSSLCiphers());
-    sslConfig.setEnabled(getDistributionConfig().getJmxManagerSSLEnabled());
-    sslConfig.setKeystore(getDistributionConfig().getJmxManagerSSLKeyStore());
-    sslConfig.setKeystorePassword(getDistributionConfig().getJmxManagerSSLKeyStorePassword());
-    sslConfig.setKeystoreType(getDistributionConfig().getJmxManagerSSLKeyStoreType());
-    sslConfig.setTruststore(getDistributionConfig().getJmxManagerSSLTrustStore());
-    sslConfig.setTruststorePassword(getDistributionConfig().getJmxManagerSSLTrustStorePassword());
-    sslConfig.setTruststoreType(getDistributionConfig().getJmxManagerSSLKeyStoreType());
-    sslConfig.setProtocols(getDistributionConfig().getJmxManagerSSLProtocols());
-    sslConfig.setRequireAuth(getDistributionConfig().getJmxManagerSSLRequireAuthentication());
+  private SSLConfig configureLegacyJMXSSL(final DistributionConfig distributionConfig,
+      final SSLConfig sslConfig) {
+    sslConfig.setCiphers(distributionConfig.getJmxManagerSSLCiphers());
+    sslConfig.setEnabled(distributionConfig.getJmxManagerSSLEnabled());
+    sslConfig.setKeystore(distributionConfig.getJmxManagerSSLKeyStore());
+    sslConfig.setKeystorePassword(distributionConfig.getJmxManagerSSLKeyStorePassword());
+    sslConfig.setKeystoreType(distributionConfig.getJmxManagerSSLKeyStoreType());
+    sslConfig.setTruststore(distributionConfig.getJmxManagerSSLTrustStore());
+    sslConfig.setTruststorePassword(distributionConfig.getJmxManagerSSLTrustStorePassword());
+    sslConfig.setTruststoreType(distributionConfig.getJmxManagerSSLKeyStoreType());
+    sslConfig.setProtocols(distributionConfig.getJmxManagerSSLProtocols());
+    sslConfig.setRequireAuth(distributionConfig.getJmxManagerSSLRequireAuthentication());
     return sslConfig;
   }
 
@@ -249,16 +264,17 @@ public class SSLConfigurationFactory {
    * @return A sslConfig object describing the ssl config for the gateway component
    * @deprecated as of Geode 1.0
    */
-  private SSLConfig configureLegacyGatewaySSL(SSLConfig sslConfig) {
-    sslConfig.setCiphers(getDistributionConfig().getGatewaySSLCiphers());
-    sslConfig.setEnabled(getDistributionConfig().getGatewaySSLEnabled());
-    sslConfig.setKeystore(getDistributionConfig().getGatewaySSLKeyStore());
-    sslConfig.setKeystorePassword(getDistributionConfig().getGatewaySSLKeyStorePassword());
-    sslConfig.setKeystoreType(getDistributionConfig().getGatewaySSLKeyStoreType());
-    sslConfig.setTruststore(getDistributionConfig().getGatewaySSLTrustStore());
-    sslConfig.setTruststorePassword(getDistributionConfig().getGatewaySSLTrustStorePassword());
-    sslConfig.setProtocols(getDistributionConfig().getGatewaySSLProtocols());
-    sslConfig.setRequireAuth(getDistributionConfig().getGatewaySSLRequireAuthentication());
+  private SSLConfig configureLegacyGatewaySSL(final DistributionConfig distributionConfig,
+      final SSLConfig sslConfig) {
+    sslConfig.setCiphers(distributionConfig.getGatewaySSLCiphers());
+    sslConfig.setEnabled(distributionConfig.getGatewaySSLEnabled());
+    sslConfig.setKeystore(distributionConfig.getGatewaySSLKeyStore());
+    sslConfig.setKeystorePassword(distributionConfig.getGatewaySSLKeyStorePassword());
+    sslConfig.setKeystoreType(distributionConfig.getGatewaySSLKeyStoreType());
+    sslConfig.setTruststore(distributionConfig.getGatewaySSLTrustStore());
+    sslConfig.setTruststorePassword(distributionConfig.getGatewaySSLTrustStorePassword());
+    sslConfig.setProtocols(distributionConfig.getGatewaySSLProtocols());
+    sslConfig.setRequireAuth(distributionConfig.getGatewaySSLRequireAuthentication());
     return sslConfig;
   }
 
@@ -268,17 +284,18 @@ public class SSLConfigurationFactory {
    * @return A sslConfig object describing the ssl config for the http service component
    * @deprecated as of Geode 1.0
    */
-  private SSLConfig configureLegacyHttpServiceSSL(SSLConfig sslConfig) {
-    sslConfig.setCiphers(getDistributionConfig().getHttpServiceSSLCiphers());
-    sslConfig.setEnabled(getDistributionConfig().getHttpServiceSSLEnabled());
-    sslConfig.setKeystore(getDistributionConfig().getHttpServiceSSLKeyStore());
-    sslConfig.setKeystorePassword(getDistributionConfig().getHttpServiceSSLKeyStorePassword());
-    sslConfig.setKeystoreType(getDistributionConfig().getHttpServiceSSLKeyStoreType());
-    sslConfig.setTruststore(getDistributionConfig().getHttpServiceSSLTrustStore());
-    sslConfig.setTruststorePassword(getDistributionConfig().getHttpServiceSSLTrustStorePassword());
-    sslConfig.setTruststoreType(getDistributionConfig().getHttpServiceSSLKeyStoreType());
-    sslConfig.setProtocols(getDistributionConfig().getHttpServiceSSLProtocols());
-    sslConfig.setRequireAuth(getDistributionConfig().getHttpServiceSSLRequireAuthentication());
+  private SSLConfig configureLegacyHttpServiceSSL(final DistributionConfig distributionConfig,
+      final SSLConfig sslConfig) {
+    sslConfig.setCiphers(distributionConfig.getHttpServiceSSLCiphers());
+    sslConfig.setEnabled(distributionConfig.getHttpServiceSSLEnabled());
+    sslConfig.setKeystore(distributionConfig.getHttpServiceSSLKeyStore());
+    sslConfig.setKeystorePassword(distributionConfig.getHttpServiceSSLKeyStorePassword());
+    sslConfig.setKeystoreType(distributionConfig.getHttpServiceSSLKeyStoreType());
+    sslConfig.setTruststore(distributionConfig.getHttpServiceSSLTrustStore());
+    sslConfig.setTruststorePassword(distributionConfig.getHttpServiceSSLTrustStorePassword());
+    sslConfig.setTruststoreType(distributionConfig.getHttpServiceSSLKeyStoreType());
+    sslConfig.setProtocols(distributionConfig.getHttpServiceSSLProtocols());
+    sslConfig.setRequireAuth(distributionConfig.getHttpServiceSSLRequireAuthentication());
     return sslConfig;
   }
 
@@ -357,4 +374,15 @@ public class SSLConfigurationFactory {
 
     return sslConfig;
   }
+
+  public static SSLConfig getSSLConfigForComponent(DistributionConfig distributionConfig,
+      SecurableCommunicationChannel sslEnabledComponent) {
+    return getInstance().createSSLConfigForComponent(distributionConfig, sslEnabledComponent);
+  }
+
+  public static SSLConfig getSSLConfigForComponent(Properties properties,
+      SecurableCommunicationChannel sslEnabledComponent) {
+    return getInstance().createSSLConfigForComponent(new DistributionConfigImpl(properties),
+        sslEnabledComponent);
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java b/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java
index eb71d38..dcf9b22 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java
@@ -19,14 +19,16 @@ import java.io.DataOutput;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
-import java.util.Map;
 import java.util.Properties;
 
-import org.apache.geode.distributed.internal.DistributionConfigImpl;
+import org.apache.geode.distributed.internal.tcpserver.LocatorCancelException;
 import org.apache.geode.distributed.internal.tcpserver.TcpClient;
 import org.apache.geode.internal.DataSerializableFixedID;
 import org.apache.geode.internal.Version;
-import org.apache.geode.internal.net.*;
+import org.apache.geode.internal.admin.SSLConfig;
+import org.apache.geode.internal.net.SSLConfigurationFactory;
+import org.apache.geode.internal.net.SocketCreator;
+import org.apache.geode.internal.security.SecurableCommunicationChannel;
 
 /**
  * Sent to a locator to request it to find (and possibly start) a jmx manager for us. It returns a
@@ -37,10 +39,6 @@ import org.apache.geode.internal.net.*;
  */
 public class JmxManagerLocatorRequest implements DataSerializableFixedID {
 
-  public JmxManagerLocatorRequest() {
-    super();
-  }
-
   public void fromData(DataInput in) throws IOException, ClassNotFoundException {}
 
   public void toData(DataOutput out) throws IOException {}
@@ -69,38 +67,25 @@ public class JmxManagerLocatorRequest implements DataSerializableFixedID {
    *         have trouble communicating with it.
    */
   public static JmxManagerLocatorResponse send(String locatorHost, int locatorPort, int msTimeout,
-      Map<String, String> sslConfigProps) throws IOException {
-    Properties distributionConfigProps = new Properties();
+      Properties sslConfigProps) throws IOException, ClassNotFoundException {
     InetAddress networkAddress = InetAddress.getByName(locatorHost);
     InetSocketAddress inetSockAddr = new InetSocketAddress(networkAddress, locatorPort);
 
-    try {
-      if (sslConfigProps != null) {
-        distributionConfigProps.putAll(sslConfigProps);
-      }
-
-      TcpClient client = new TcpClient(new DistributionConfigImpl(distributionConfigProps));
-      Object responseFromServer = client.requestToServer(inetSockAddr, SINGLETON, msTimeout, true);
+    // simply need to turn sslConfigProps into sslConfig for locator
+    SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(sslConfigProps,
+        SecurableCommunicationChannel.LOCATOR);
+    SocketCreator socketCreator = new SocketCreator(sslConfig);
+    TcpClient client = new TcpClient(socketCreator);
+    Object responseFromServer = client.requestToServer(inetSockAddr, SINGLETON, msTimeout, true);
 
+    if (responseFromServer instanceof JmxManagerLocatorResponse)
       return (JmxManagerLocatorResponse) responseFromServer;
-    } catch (ClassNotFoundException unexpected) {
-      throw new IllegalStateException(unexpected);
-    } catch (ClassCastException unexpected) {
-      // FIXME - Abhishek: object read is type "int" instead of
-      // JmxManagerLocatorResponse when the Locator is using SSL & the request
-      // didn't use SSL -> this causes ClassCastException. Not sure how to make
-      // locator meaningful message
-      throw new IllegalStateException(unexpected);
-    } finally {
-      distributionConfigProps.clear();
+    else {
+      throw new LocatorCancelException(
+          "Unrecognisable response received: This could be the result of trying to connect a non-SSL-enabled client to an SSL-enabled locator.");
     }
   }
 
-  public static JmxManagerLocatorResponse send(String locatorHost, int locatorPort, int msTimeout)
-      throws IOException {
-    return send(locatorHost, locatorPort, msTimeout, null);
-  }
-
   @Override
   public Version[] getSerializationVersions() {
     // TODO Auto-generated method stub

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java b/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java
index 16d45bc..31a198b 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java
@@ -308,6 +308,7 @@ public class BeanUtilFuncs {
     gemFirePropertyData.setSSLKeyStore(config.getSSLKeyStore());
     gemFirePropertyData.setSSLKeyStoreType(config.getSSLKeyStoreType());
     gemFirePropertyData.setSSLKeyStorePassword(config.getSSLKeyStorePassword());
+
     gemFirePropertyData.setSSLTrustStore(config.getSSLTrustStore());
     gemFirePropertyData.setSSLTrustStorePassword(config.getSSLTrustStorePassword());
     gemFirePropertyData.setSSLTrustStoreType(config.getSSLTrustStoreType());

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
index 3e1357d..1b84649 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
@@ -16,8 +16,6 @@ package org.apache.geode.management.internal.cli;
 
 import org.apache.geode.management.internal.cli.shell.Gfsh;
 
-import java.io.IOException;
-
 /**
  * Semi-complete implementation of {@link CliAroundInterceptor} for convenience for implementors.
  * 
@@ -66,7 +64,7 @@ public abstract class AbstractCliAroundInterceptor implements CliAroundIntercept
     return gfsh != null && !gfsh.isQuietMode() && !gfsh.isHeadlessMode();
   }
 
-  protected String interact(String message) throws IOException {
+  protected String interact(String message) {
     return Gfsh.getCurrentInstance().interact(message);
   }
 
@@ -83,18 +81,12 @@ public abstract class AbstractCliAroundInterceptor implements CliAroundIntercept
 
     Response response = null;
     do {
-      try {
-        String userInput = interact(message);
-
-        if (isNullOrEmpty(userInput)) {
-          return defaultResponse;
-        }
-        response = Response.fromString(userInput);
+      String userInput = interact(message);
 
-      } catch (IOException ioex) {
-        severe("Could not read user response", ioex);
-        // What can you do except try again???
+      if (isNullOrEmpty(userInput)) {
+        return defaultResponse;
       }
+      response = Response.fromString(userInput);
 
     } while (response == null);
 

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java
index be556a4..274f61c 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java
@@ -15,26 +15,19 @@
 
 package org.apache.geode.management.internal.cli.commands;
 
-import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_CIPHERS;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
-import static org.apache.geode.management.internal.cli.shell.Gfsh.SSL_ENABLED_CIPHERS;
-import static org.apache.geode.management.internal.cli.shell.Gfsh.SSL_ENABLED_PROTOCOLS;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_PREFIX;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_PREFIX;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_PREFIX;
 
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.net.URL;
+import java.net.MalformedURLException;
 import java.security.KeyStore;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
+import java.util.Arrays;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
 
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.KeyManagerFactory;
@@ -46,16 +39,16 @@ import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
 import org.apache.geode.internal.DSFIDFactory;
+import org.apache.geode.internal.admin.SSLConfig;
 import org.apache.geode.internal.lang.Initializer;
-import org.apache.geode.internal.util.IOUtils;
-import org.apache.geode.internal.util.PasswordUtil;
+import org.apache.geode.internal.net.SSLConfigurationFactory;
+import org.apache.geode.internal.security.SecurableCommunicationChannel;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.Result;
 import org.apache.geode.management.internal.JmxManagerLocatorRequest;
 import org.apache.geode.management.internal.JmxManagerLocatorResponse;
 import org.apache.geode.management.internal.SSLUtil;
-import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.LogWrapper;
 import org.apache.geode.management.internal.cli.converters.ConnectionEndpointConverter;
 import org.apache.geode.management.internal.cli.domain.ConnectToLocatorResult;
@@ -65,6 +58,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.cli.shell.Gfsh;
 import org.apache.geode.management.internal.cli.shell.JmxOperationInvoker;
 import org.apache.geode.management.internal.cli.util.ConnectionEndpoint;
+import org.apache.geode.management.internal.security.ResourceConstants;
 import org.apache.geode.management.internal.web.domain.LinkIndex;
 import org.apache.geode.management.internal.web.http.support.SimpleHttpRequester;
 import org.apache.geode.management.internal.web.shell.HttpOperationInvoker;
@@ -75,6 +69,12 @@ public class ConnectCommand implements GfshCommand {
   // millis that connect --locator will wait for a response from the locator.
   public final static int CONNECT_LOCATOR_TIMEOUT_MS = 60000; // see bug 45971
 
+  static UserInputProperty[] USERINPUTPROPERTIES =
+      {UserInputProperty.KEYSTORE, UserInputProperty.KEYSTORE_PASSWORD,
+          UserInputProperty.KEYSTORE_TYPE, UserInputProperty.TRUSTSTORE,
+          UserInputProperty.TRUSTSTORE_PASSWORD, UserInputProperty.TRUSTSTORE_TYPE,
+          UserInputProperty.CIPHERS, UserInputProperty.PROTOCOL, UserInputProperty.COMPONENT};
+
   @CliCommand(value = {CliStrings.CONNECT}, help = CliStrings.CONNECT__HELP)
   @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH, CliStrings.TOPIC_GEODE_JMX,
       CliStrings.TOPIC_GEODE_MANAGER})
@@ -82,118 +82,178 @@ public class ConnectCommand implements GfshCommand {
       @CliOption(key = {CliStrings.CONNECT__LOCATOR},
           unspecifiedDefaultValue = ConnectionEndpointConverter.DEFAULT_LOCATOR_ENDPOINTS,
           optionContext = ConnectionEndpoint.LOCATOR_OPTION_CONTEXT,
-          help = CliStrings.CONNECT__LOCATOR__HELP) ConnectionEndpoint locatorTcpHostPort,
+          help = CliStrings.CONNECT__LOCATOR__HELP) ConnectionEndpoint locatorEndPoint,
       @CliOption(key = {CliStrings.CONNECT__JMX_MANAGER},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           optionContext = ConnectionEndpoint.JMXMANAGER_OPTION_CONTEXT,
-          help = CliStrings.CONNECT__JMX_MANAGER__HELP) ConnectionEndpoint memberRmiHostPort,
-      @CliOption(key = {CliStrings.CONNECT__USE_HTTP}, mandatory = false,
-          specifiedDefaultValue = "true", unspecifiedDefaultValue = "false",
+          help = CliStrings.CONNECT__JMX_MANAGER__HELP) ConnectionEndpoint jmxManagerEndPoint,
+      @CliOption(key = {CliStrings.CONNECT__USE_HTTP}, specifiedDefaultValue = "true",
+          unspecifiedDefaultValue = "false",
           help = CliStrings.CONNECT__USE_HTTP__HELP) boolean useHttp,
-      @CliOption(key = {CliStrings.CONNECT__URL}, mandatory = false,
+      @CliOption(key = {CliStrings.CONNECT__URL},
           unspecifiedDefaultValue = CliStrings.CONNECT__DEFAULT_BASE_URL,
           help = CliStrings.CONNECT__URL__HELP) String url,
       @CliOption(key = {CliStrings.CONNECT__USERNAME},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__USERNAME__HELP) String userName,
       @CliOption(key = {CliStrings.CONNECT__PASSWORD},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__PASSWORD__HELP) String password,
       @CliOption(key = {CliStrings.CONNECT__KEY_STORE},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__KEY_STORE__HELP) String keystore,
       @CliOption(key = {CliStrings.CONNECT__KEY_STORE_PASSWORD},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__KEY_STORE_PASSWORD__HELP) String keystorePassword,
       @CliOption(key = {CliStrings.CONNECT__TRUST_STORE},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__TRUST_STORE__HELP) String truststore,
       @CliOption(key = {CliStrings.CONNECT__TRUST_STORE_PASSWORD},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__TRUST_STORE_PASSWORD__HELP) String truststorePassword,
       @CliOption(key = {CliStrings.CONNECT__SSL_CIPHERS},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__SSL_CIPHERS__HELP) String sslCiphers,
       @CliOption(key = {CliStrings.CONNECT__SSL_PROTOCOLS},
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.CONNECT__SSL_PROTOCOLS__HELP) String sslProtocols,
-      @CliOption(key = CliStrings.CONNECT__SECURITY_PROPERTIES,
-          optionContext = ConverterHint.FILE_PATH,
-          unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
-          help = CliStrings.CONNECT__SECURITY_PROPERTIES__HELP) final String gfSecurityPropertiesPath,
+      @CliOption(key = CliStrings.CONNECT__SECURITY_PROPERTIES, optionContext = ConverterHint.FILE,
+          help = CliStrings.CONNECT__SECURITY_PROPERTIES__HELP) final File gfSecurityPropertiesFile,
       @CliOption(key = {CliStrings.CONNECT__USE_SSL}, specifiedDefaultValue = "true",
           unspecifiedDefaultValue = "false",
-          help = CliStrings.CONNECT__USE_SSL__HELP) final boolean useSsl) {
-    Result result;
-    String passwordToUse = PasswordUtil.decrypt(password);
-    String keystoreToUse = keystore;
-    String keystorePasswordToUse = keystorePassword;
-    String truststoreToUse = truststore;
-    String truststorePasswordToUse = truststorePassword;
-    String sslCiphersToUse = sslCiphers;
-    String sslProtocolsToUse = sslProtocols;
+          help = CliStrings.CONNECT__USE_SSL__HELP) boolean useSsl)
+      throws MalformedURLException {
 
+    Result result;
     Gfsh gfsh = getGfsh();
+
+    // bail out if gfsh is already connected.
     if (gfsh != null && gfsh.isConnectedAndReady()) {
       return ResultBuilder
           .createInfoResult("Already connected to: " + getGfsh().getOperationInvoker().toString());
     }
 
-    Map<String, String> sslConfigProps = null;
-    try {
-      if (userName != null && userName.length() > 0) {
-        if (passwordToUse == null || passwordToUse.length() == 0) {
-          passwordToUse = gfsh.readPassword(CliStrings.CONNECT__PASSWORD + ": ");
-        }
-        if (passwordToUse == null || passwordToUse.length() == 0) {
-          return ResultBuilder
-              .createConnectionErrorResult(CliStrings.CONNECT__MSG__JMX_PASSWORD_MUST_BE_SPECIFIED);
-        }
-      }
+    // ssl options are passed in in the order defined in USERINPUTPROPERTIES, note the two types
+    // are null, because we don't have connect command options for them yet
+    Properties gfProperties = resolveSslProperties(gfsh, useSsl, null, gfSecurityPropertiesFile,
+        keystore, keystorePassword, null, truststore, truststorePassword, null, sslCiphers,
+        sslProtocols, null);
 
-      sslConfigProps = this.readSSLConfiguration(useSsl, keystoreToUse, keystorePasswordToUse,
-          truststoreToUse, truststorePasswordToUse, sslCiphersToUse, sslProtocolsToUse,
-          gfSecurityPropertiesPath);
-    } catch (IOException e) {
-      return handleExcpetion(e, null);
+    if (containsSSLConfig(gfProperties) || containsLegacySSLConfig(gfProperties)) {
+      useSsl = true;
+    }
+
+    // if username is specified in the option but password is not, prompt for the password
+    // note if gfProperties has username but no password, we would not prompt for password yet,
+    // because we may not need username/password combination to connect.
+    if (userName != null) {
+      gfProperties.setProperty(ResourceConstants.USER_NAME, userName);
+      if (password == null) {
+        password = UserInputProperty.PASSWORD.promptForAcceptableValue(gfsh);
+      }
+      gfProperties.setProperty(UserInputProperty.PASSWORD.getKey(), password);
     }
 
+    // TODO: refactor this to be more readable, like
+    /*
+     * if(useHttp) connectOverHttp else if(jmxManagerEndPoint==null) connectToLocator to get the
+     * jmxManagerEndPoint else connectTo jmxManagerEndPoint
+     */
     if (useHttp) {
-      result = httpConnect(sslConfigProps, useSsl, url, userName, passwordToUse);
+      result = httpConnect(gfProperties, url);
     } else {
-      result = jmxConnect(sslConfigProps, memberRmiHostPort, locatorTcpHostPort, useSsl, userName,
-          passwordToUse, gfSecurityPropertiesPath, false);
+      result = jmxConnect(gfProperties, useSsl, jmxManagerEndPoint, locatorEndPoint, false);
     }
 
     return result;
   }
 
+  /**
+   *
+   * @param gfsh
+   * @param useSsl if true, and no files/options passed, we would still insist on prompting for ssl
+   *        config (considered only when the last three parameters are null)
+   * @param gfPropertiesFile gemfire properties file, can be null
+   * @param gfSecurityPropertiesFile gemfire security properties file, can be null
+   * @param sslOptionValues an array of 9 in this order, as defined in USERINPUTPROPERTIES
+   * @return the properties
+   */
+  Properties resolveSslProperties(Gfsh gfsh, boolean useSsl, File gfPropertiesFile,
+      File gfSecurityPropertiesFile, String... sslOptionValues) {
 
-  private Result httpConnect(Map<String, String> sslConfigProps, boolean useSsl, String url,
-      String userName, String passwordToUse) {
-    Gfsh gfsh = getGfsh();
-    try {
-      Map<String, String> securityProperties = new HashMap<String, String>();
+    // first trying to load the sslProperties from the file
+    Properties gfProperties = loadProperties(gfPropertiesFile, gfSecurityPropertiesFile);
 
-      // at this point, if userName is not empty, password should not be empty either
-      if (userName != null && userName.length() > 0) {
-        securityProperties.put("security-username", userName);
-        securityProperties.put("security-password", passwordToUse);
+    // if the security file is a legacy ssl security file, then the rest of the command options, if
+    // any, are ignored. Because we are not trying to add/replace the legacy ssl values using the
+    // command line values. all command line ssl values updates the ssl-* options.
+    if (containsLegacySSLConfig(gfProperties)) {
+      return gfProperties;
+    }
+
+    // if nothing indicates we should prompt for missing ssl config info, return immediately
+    if (!(useSsl || containsSSLConfig(gfProperties) || isSslImpliedBySslOptions(sslOptionValues))) {
+      return gfProperties;
+    }
+
+    // if use ssl is implied by any of the options, then command option will add to/update the
+    // properties loaded from file. If the ssl config is not specified anywhere, prompt user for it.
+    for (int i = 0; i < USERINPUTPROPERTIES.length; i++) {
+      UserInputProperty userInputProperty = USERINPUTPROPERTIES[i];
+      String sslOptionValue = null;
+      if (sslOptionValues != null && sslOptionValues.length > i) {
+        sslOptionValue = sslOptionValues[i];
       }
+      String sslConfigValue = gfProperties.getProperty(userInputProperty.getKey());
 
-      if (useSsl) {
-        configureHttpsURLConnection(sslConfigProps);
+      // if this option is specified, always use this value
+      if (sslOptionValue != null) {
+        gfProperties.setProperty(userInputProperty.getKey(), sslOptionValue);
+      }
+      // if option is not specified and not present in the original properties, prompt for it
+      else if (sslConfigValue == null) {
+        gfProperties.setProperty(userInputProperty.getKey(),
+            userInputProperty.promptForAcceptableValue(gfsh));
+      }
+    }
+
+    return gfProperties;
+  }
+
+  boolean isSslImpliedBySslOptions(String... sslOptions) {
+    if (sslOptions == null) {
+      return false;
+    }
+    return Arrays.stream(sslOptions).anyMatch(Objects::nonNull);
+  }
+
+  Properties loadProperties(File... files) {
+    Properties properties = new Properties();
+    if (files == null) {
+      return properties;
+    }
+    for (File file : files) {
+      if (file != null) {
+        properties.putAll(ShellCommands.loadProperties(file));
+      }
+    }
+    return properties;
+  }
+
+  static boolean containsLegacySSLConfig(Properties properties) {
+    return properties.stringPropertyNames().stream()
+        .anyMatch(key -> key.startsWith(CLUSTER_SSL_PREFIX)
+            || key.startsWith(JMX_MANAGER_SSL_PREFIX) || key.startsWith(HTTP_SERVICE_SSL_PREFIX));
+  }
+
+  static boolean containsSSLConfig(Properties properties) {
+    return properties.stringPropertyNames().stream().anyMatch(key -> key.startsWith("ssl-"));
+  }
+
+
+  Result httpConnect(Properties gfProperties, String url) {
+    Gfsh gfsh = getGfsh();
+    try {
+      SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(gfProperties,
+          SecurableCommunicationChannel.WEB);
+      if (sslConfig.isEnabled()) {
+        configureHttpsURLConnection(sslConfig);
         if (url.startsWith("http:")) {
           url = url.replace("http:", "https:");
         }
       }
 
-      Iterator<String> it = sslConfigProps.keySet().iterator();
-      while (it.hasNext()) {
-        String secKey = it.next();
-        securityProperties.put(secKey, sslConfigProps.get(secKey));
-      }
-
       // This is so that SSL termination results in https URLs being returned
       String query = (url.startsWith("https")) ? "?scheme=https" : "";
 
@@ -201,14 +261,14 @@ public class ConnectCommand implements GfshCommand {
           "Sending HTTP request for Link Index at (%1$s)...", url.concat("/index").concat(query)));
 
       LinkIndex linkIndex =
-          new SimpleHttpRequester(gfsh, CONNECT_LOCATOR_TIMEOUT_MS, securityProperties)
+          new SimpleHttpRequester(gfsh, CONNECT_LOCATOR_TIMEOUT_MS, (Map) gfProperties)
               .exchange(url.concat("/index").concat(query), LinkIndex.class);
 
       LogWrapper.getInstance()
           .warning(String.format("Received Link Index (%1$s)", linkIndex.toString()));
 
       HttpOperationInvoker operationInvoker =
-          new RestHttpOperationInvoker(linkIndex, gfsh, url, securityProperties);
+          new RestHttpOperationInvoker(linkIndex, gfsh, url, (Map) gfProperties);
 
       Initializer.init(operationInvoker);
       gfsh.setOperationInvoker(operationInvoker);
@@ -226,244 +286,103 @@ public class ConnectCommand implements GfshCommand {
 
       // if it's security exception, and we already sent in username and password, still retuns the
       // connection error
-      if (userName != null) {
+      if (gfProperties.containsKey(ResourceConstants.USER_NAME)) {
         return handleExcpetion(e, null);
       }
 
       // otherwise, prompt for username and password and retry the conenction
-      try {
-        userName = gfsh.readText(CliStrings.CONNECT__USERNAME + ": ");
-        passwordToUse = gfsh.readPassword(CliStrings.CONNECT__PASSWORD + ": ");
-        return httpConnect(sslConfigProps, useSsl, url, userName, passwordToUse);
-      } catch (IOException ioe) {
-        return handleExcpetion(ioe, null);
-      }
+      gfProperties.setProperty(UserInputProperty.USERNAME.getKey(),
+          UserInputProperty.USERNAME.promptForAcceptableValue(gfsh));
+      gfProperties.setProperty(UserInputProperty.PASSWORD.getKey(),
+          UserInputProperty.PASSWORD.promptForAcceptableValue(gfsh));
+      return httpConnect(gfProperties, url);
+
     } finally {
       Gfsh.redirectInternalJavaLoggers();
     }
   }
 
-  private Result jmxConnect(Map<String, String> sslConfigProps,
-      ConnectionEndpoint memberRmiHostPort, ConnectionEndpoint locatorTcpHostPort, boolean useSsl,
-      String userName, String passwordToUse, String gfSecurityPropertiesPath, boolean retry) {
-    ConnectionEndpoint hostPortToConnect = null;
+  Result jmxConnect(Properties gfProperties, boolean useSsl, ConnectionEndpoint memberRmiHostPort,
+      ConnectionEndpoint locatorTcpHostPort, boolean retry) {
+    ConnectionEndpoint jmxHostPortToConnect = null;
     Gfsh gfsh = getGfsh();
 
     try {
-
-      // trying to find the hostPortToConnect, if rmi host port exists, use that, otherwise, use
+      // trying to find the rmi host and port, if rmi host port exists, use that, otherwise, use
       // locator to find the rmi host port
       if (memberRmiHostPort != null) {
-        hostPortToConnect = memberRmiHostPort;
+        jmxHostPortToConnect = memberRmiHostPort;
       } else {
-        // Props required to configure a SocketCreator with SSL.
-        // Used for gfsh->locator connection & not needed for gfsh->manager connection
-        if (useSsl || !sslConfigProps.isEmpty()) {
-          sslConfigProps.put(MCAST_PORT, String.valueOf(0));
-          sslConfigProps.put(LOCATORS, "");
-
-          String sslInfoLogMsg = "Connecting to Locator via SSL.";
-          if (useSsl) {
-            sslInfoLogMsg = CliStrings.CONNECT__USE_SSL + " is set to true. " + sslInfoLogMsg;
-          }
-          gfsh.logToFile(sslInfoLogMsg, null);
+        if (useSsl) {
+          gfsh.logToFile(
+              CliStrings.CONNECT__USE_SSL + " is set to true. Connecting to Locator via SSL.",
+              null);
         }
 
         Gfsh.println(CliStrings.format(CliStrings.CONNECT__MSG__CONNECTING_TO_LOCATOR_AT_0,
             new Object[] {locatorTcpHostPort.toString(false)}));
         ConnectToLocatorResult connectToLocatorResult =
             connectToLocator(locatorTcpHostPort.getHost(), locatorTcpHostPort.getPort(),
-                CONNECT_LOCATOR_TIMEOUT_MS, sslConfigProps);
-        hostPortToConnect = connectToLocatorResult.getMemberEndpoint();
+                CONNECT_LOCATOR_TIMEOUT_MS, gfProperties);
+        jmxHostPortToConnect = connectToLocatorResult.getMemberEndpoint();
 
         // when locator is configured to use SSL (ssl-enabled=true) but manager is not
         // (jmx-manager-ssl=false)
-        if ((useSsl || !sslConfigProps.isEmpty())
-            && !connectToLocatorResult.isJmxManagerSslEnabled()) {
+        if (useSsl && !connectToLocatorResult.isJmxManagerSslEnabled()) {
           gfsh.logInfo(
               CliStrings.CONNECT__USE_SSL
                   + " is set to true. But JMX Manager doesn't support SSL, connecting without SSL.",
               null);
-          sslConfigProps.clear();
+          useSsl = false;
         }
       }
 
-      if (!sslConfigProps.isEmpty()) {
+      if (useSsl) {
         gfsh.logToFile("Connecting to manager via SSL.", null);
       }
 
       // print out the connecting endpoint
       if (!retry) {
         Gfsh.println(CliStrings.format(CliStrings.CONNECT__MSG__CONNECTING_TO_MANAGER_AT_0,
-            new Object[] {hostPortToConnect.toString(false)}));
+            new Object[] {jmxHostPortToConnect.toString(false)}));
       }
 
       InfoResultData infoResultData = ResultBuilder.createInfoResultData();
-      JmxOperationInvoker operationInvoker =
-          new JmxOperationInvoker(hostPortToConnect.getHost(), hostPortToConnect.getPort(),
-              userName, passwordToUse, sslConfigProps, gfSecurityPropertiesPath);
+      JmxOperationInvoker operationInvoker = new JmxOperationInvoker(jmxHostPortToConnect.getHost(),
+          jmxHostPortToConnect.getPort(), gfProperties);
 
       gfsh.setOperationInvoker(operationInvoker);
-      infoResultData.addLine(
-          CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, hostPortToConnect.toString(false)));
-      LogWrapper.getInstance().info(
-          CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, hostPortToConnect.toString(false)));
+      infoResultData.addLine(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS,
+          jmxHostPortToConnect.toString(false)));
+      LogWrapper.getInstance().info(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS,
+          jmxHostPortToConnect.toString(false)));
       return ResultBuilder.buildResult(infoResultData);
     } catch (Exception e) {
       // all other exceptions, just logs it and returns a connection error
       if (!(e instanceof SecurityException) && !(e instanceof AuthenticationFailedException)) {
-        return handleExcpetion(e, hostPortToConnect);
+        return handleExcpetion(e, jmxHostPortToConnect);
       }
 
       // if it's security exception, and we already sent in username and password, still returns the
       // connection error
-      if (userName != null) {
-        return handleExcpetion(e, hostPortToConnect);
+      if (gfProperties.containsKey(ResourceConstants.USER_NAME)) {
+        return handleExcpetion(e, jmxHostPortToConnect);
       }
 
       // otherwise, prompt for username and password and retry the conenction
-      try {
-        userName = gfsh.readText(CliStrings.CONNECT__USERNAME + ": ");
-        passwordToUse = gfsh.readPassword(CliStrings.CONNECT__PASSWORD + ": ");
-        // GEODE-2250 If no value for both username and password, at this point we need to error to
-        // avoid a stack overflow.
-        if (userName == null && passwordToUse == null)
-          return handleExcpetion(e, hostPortToConnect);
-        return jmxConnect(sslConfigProps, hostPortToConnect, null, useSsl, userName, passwordToUse,
-            gfSecurityPropertiesPath, true);
-      } catch (IOException ioe) {
-        return handleExcpetion(ioe, hostPortToConnect);
-      }
+      gfProperties.setProperty(UserInputProperty.USERNAME.getKey(),
+          UserInputProperty.USERNAME.promptForAcceptableValue(gfsh));
+      gfProperties.setProperty(UserInputProperty.PASSWORD.getKey(),
+          UserInputProperty.PASSWORD.promptForAcceptableValue(gfsh));
+      return jmxConnect(gfProperties, useSsl, jmxHostPortToConnect, null, true);
+
     } finally {
       Gfsh.redirectInternalJavaLoggers();
     }
   }
 
-  /**
-   * Common code to read SSL information. Used by JMX, Locator & HTTP mode connect
-   */
-  private Map<String, String> readSSLConfiguration(boolean useSsl, String keystoreToUse,
-      String keystorePasswordToUse, String truststoreToUse, String truststorePasswordToUse,
-      String sslCiphersToUse, String sslProtocolsToUse, String gfSecurityPropertiesPath)
-      throws IOException {
-
-    Gfsh gfshInstance = getGfsh();
-    final Map<String, String> sslConfigProps = new LinkedHashMap<String, String>();
-
-    // JMX SSL Config 1:
-    // First from gfsecurity properties file if it's specified OR
-    // if the default gfsecurity.properties exists useSsl==true
-    if (useSsl || gfSecurityPropertiesPath != null) {
-      // reference to hold resolved gfSecurityPropertiesPath
-      String gfSecurityPropertiesPathToUse = CliUtil.resolvePathname(gfSecurityPropertiesPath);
-      URL gfSecurityPropertiesUrl = null;
-
-      // Case 1: User has specified gfSecurity properties file
-      if (StringUtils.isNotBlank(gfSecurityPropertiesPathToUse)) {
-        // User specified gfSecurity properties doesn't exist
-        if (!IOUtils.isExistingPathname(gfSecurityPropertiesPathToUse)) {
-          gfshInstance
-              .printAsSevere(CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE,
-                  "Security ", gfSecurityPropertiesPathToUse));
-        } else {
-          gfSecurityPropertiesUrl = new File(gfSecurityPropertiesPathToUse).toURI().toURL();
-        }
-      } else if (useSsl && gfSecurityPropertiesPath == null) {
-        // Case 2: User has specified to useSsl but hasn't specified
-        // gfSecurity properties file. Use default "gfsecurity.properties"
-        // in current dir, user's home or classpath
-        gfSecurityPropertiesUrl = ShellCommands.getFileUrl("gfsecurity.properties");
-      }
-      // if 'gfSecurityPropertiesPath' OR gfsecurity.properties has resolvable path
-      if (gfSecurityPropertiesUrl != null) {
-        gfshInstance.logToFile("Using security properties file : "
-            + CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath()), null);
-        Map<String, String> gfsecurityProps =
-            ShellCommands.loadPropertiesFromURL(gfSecurityPropertiesUrl);
-        // command line options (if any) would override props in gfsecurity.properties
-        sslConfigProps.putAll(gfsecurityProps);
-      }
-    }
-
-    int numTimesPrompted = 0;
-    /*
-     * Using do-while here for a case when --use-ssl=true is specified but no SSL options were
-     * specified & there was no gfsecurity properties specified or readable in default gfsh
-     * directory.
-     *
-     * NOTE: 2nd round of prompting is done only when sslConfigProps map is empty & useSsl is true -
-     * so we won't over-write any previous values.
-     */
-    do {
-      // JMX SSL Config 2: Now read the options
-      if (numTimesPrompted > 0) {
-        Gfsh.println("Please specify these SSL Configuration properties: ");
-      }
-
-      if (numTimesPrompted > 0) {
-        // NOTE: sslConfigProps map was empty
-        keystoreToUse = gfshInstance.readText(CliStrings.CONNECT__KEY_STORE + ": ");
-      }
-      if (keystoreToUse != null && keystoreToUse.length() > 0) {
-        if (keystorePasswordToUse == null || keystorePasswordToUse.length() == 0) {
-          // Check whether specified in gfsecurity props earlier
-          keystorePasswordToUse = sslConfigProps.get(SSL_KEYSTORE_PASSWORD);
-          if (keystorePasswordToUse == null || keystorePasswordToUse.length() == 0) {
-            // not even in properties file, prompt user for it
-            keystorePasswordToUse =
-                gfshInstance.readPassword(CliStrings.CONNECT__KEY_STORE_PASSWORD + ": ");
-            sslConfigProps.put(SSL_KEYSTORE_PASSWORD, keystorePasswordToUse);
-          }
-        } else {// For cases where password is already part of command option
-          sslConfigProps.put(SSL_KEYSTORE_PASSWORD, keystorePasswordToUse);
-        }
-        sslConfigProps.put(SSL_KEYSTORE, keystoreToUse);
-      }
-
-      if (numTimesPrompted > 0) {
-        truststoreToUse = gfshInstance.readText(CliStrings.CONNECT__TRUST_STORE + ": ");
-      }
-      if (truststoreToUse != null && truststoreToUse.length() > 0) {
-        if (truststorePasswordToUse == null || truststorePasswordToUse.length() == 0) {
-          // Check whether specified in gfsecurity props earlier?
-          truststorePasswordToUse = sslConfigProps.get(SSL_TRUSTSTORE_PASSWORD);
-          if (truststorePasswordToUse == null || truststorePasswordToUse.length() == 0) {
-            // not even in properties file, prompt user for it
-            truststorePasswordToUse =
-                gfshInstance.readPassword(CliStrings.CONNECT__TRUST_STORE_PASSWORD + ": ");
-            sslConfigProps.put(SSL_TRUSTSTORE_PASSWORD, truststorePasswordToUse);
-          }
-        } else {// For cases where password is already part of command option
-          sslConfigProps.put(SSL_TRUSTSTORE_PASSWORD, truststorePasswordToUse);
-        }
-        sslConfigProps.put(SSL_TRUSTSTORE, truststoreToUse);
-      }
-
-      if (numTimesPrompted > 0) {
-        sslCiphersToUse = gfshInstance.readText(CliStrings.CONNECT__SSL_CIPHERS + ": ");
-      }
-      if (sslCiphersToUse != null && sslCiphersToUse.length() > 0) {
-        // sslConfigProps.put(DistributionConfig.CLUSTER_SSL_CIPHERS_NAME, sslCiphersToUse);
-        sslConfigProps.put(SSL_ENABLED_CIPHERS, sslCiphersToUse);
-      }
-
-      if (numTimesPrompted > 0) {
-        sslProtocolsToUse = gfshInstance.readText(CliStrings.CONNECT__SSL_PROTOCOLS + ": ");
-      }
-      if (sslProtocolsToUse != null && sslProtocolsToUse.length() > 0) {
-        // sslConfigProps.put(DistributionConfig.CLUSTER_SSL_PROTOCOLS_NAME, sslProtocolsToUse);
-        sslConfigProps.put(SSL_ENABLED_PROTOCOLS, sslProtocolsToUse);
-      }
-
-      // SSL is required to be used but no SSL config found
-    } while (useSsl && sslConfigProps.isEmpty() && (0 == numTimesPrompted++)
-        && !gfshInstance.isQuietMode());
-    return sslConfigProps;
-  }
-
-
   public static ConnectToLocatorResult connectToLocator(String host, int port, int timeout,
-      Map<String, String> props) throws IOException {
+      Properties props) throws IOException, ClassNotFoundException {
     // register DSFID types first; invoked explicitly so that all message type
     // initializations do not happen in first deserialization on a possibly
     // "precious" thread
@@ -497,48 +416,34 @@ public class ConnectCommand implements GfshCommand {
         locatorResponse.isJmxManagerSslEnabled());
   }
 
-  private void configureHttpsURLConnection(Map<String, String> sslConfigProps) throws Exception {
-    String keystoreToUse = sslConfigProps.get(SSL_KEYSTORE);
-    String keystorePasswordToUse = sslConfigProps.get(SSL_KEYSTORE_PASSWORD);
-    String truststoreToUse = sslConfigProps.get(SSL_TRUSTSTORE);
-    String truststorePasswordToUse = sslConfigProps.get(SSL_TRUSTSTORE_PASSWORD);
-    // Ciphers are not passed to HttpsURLConnection. Could not find a clean way
-    // to pass this attribute to socket layer (see #51645)
-    String sslCiphersToUse = sslConfigProps.get(SSL_CIPHERS);
-    String sslProtocolsToUse = sslConfigProps.get(SSL_PROTOCOLS);
-
-    // Commenting the code to set cipher suites in GFSH rest connect (see #51645)
-    /*
-     * if(sslCiphersToUse != null){ System.setProperty("https.cipherSuites", sslCiphersToUse); }
-     */
+  private void configureHttpsURLConnection(SSLConfig sslConfig) throws Exception {
     FileInputStream keyStoreStream = null;
     FileInputStream trustStoreStream = null;
     try {
-
       KeyManagerFactory keyManagerFactory = null;
-      if (StringUtils.isNotBlank(keystoreToUse)) {
-        KeyStore clientKeys = KeyStore.getInstance("JKS");
-        keyStoreStream = new FileInputStream(keystoreToUse);
-        clientKeys.load(keyStoreStream, keystorePasswordToUse.toCharArray());
+      if (StringUtils.isNotBlank(sslConfig.getKeystore())) {
+        KeyStore clientKeys = KeyStore.getInstance(sslConfig.getKeystoreType());
+        keyStoreStream = new FileInputStream(sslConfig.getKeystore());
+        clientKeys.load(keyStoreStream, sslConfig.getKeystorePassword().toCharArray());
 
         keyManagerFactory =
             KeyManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-        keyManagerFactory.init(clientKeys, keystorePasswordToUse.toCharArray());
+        keyManagerFactory.init(clientKeys, sslConfig.getKeystorePassword().toCharArray());
       }
 
       // load server public key
       TrustManagerFactory trustManagerFactory = null;
-      if (StringUtils.isNotBlank(truststoreToUse)) {
-        KeyStore serverPub = KeyStore.getInstance("JKS");
-        trustStoreStream = new FileInputStream(truststoreToUse);
-        serverPub.load(trustStoreStream, truststorePasswordToUse.toCharArray());
+      if (StringUtils.isNotBlank(sslConfig.getTruststore())) {
+        KeyStore serverPub = KeyStore.getInstance(sslConfig.getTruststoreType());
+        trustStoreStream = new FileInputStream(sslConfig.getTruststore());
+        serverPub.load(trustStoreStream, sslConfig.getTruststorePassword().toCharArray());
         trustManagerFactory =
             TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
         trustManagerFactory.init(serverPub);
       }
 
       SSLContext ssl =
-          SSLContext.getInstance(SSLUtil.getSSLAlgo(SSLUtil.readArray(sslProtocolsToUse)));
+          SSLContext.getInstance(SSLUtil.getSSLAlgo(SSLUtil.readArray(sslConfig.getProtocols())));
 
       ssl.init(keyManagerFactory != null ? keyManagerFactory.getKeyManagers() : null,
           trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null,
@@ -552,13 +457,9 @@ public class ConnectCommand implements GfshCommand {
       if (trustStoreStream != null) {
         trustStoreStream.close();
       }
-
     }
-
-
   }
 
-
   private Result handleExcpetion(Exception e, ConnectionEndpoint hostPortToConnect) {
     String errorMessage = e.getMessage();
     if (hostPortToConnect != null) {
@@ -568,5 +469,4 @@ public class ConnectCommand implements GfshCommand {
     LogWrapper.getInstance().severe(errorMessage, e);
     return ResultBuilder.createConnectionErrorResult(errorMessage);
   }
-
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java
index 1aea253..84ee5db 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java
@@ -25,10 +25,7 @@ import java.io.InputStreamReader;
 import java.io.Writer;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.Collections;
-import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
@@ -38,7 +35,6 @@ import org.springframework.shell.core.ExitShellRequest;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
-import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.internal.ClassPathLoader;
 import org.apache.geode.internal.lang.SystemUtils;
 import org.apache.geode.internal.util.IOUtils;
@@ -62,52 +58,43 @@ import org.apache.geode.management.internal.cli.shell.jline.GfshHistory;
  * @since GemFire 7.0
  */
 public class ShellCommands implements GfshCommand {
+  static Properties loadProperties(URL url) {
+    Properties properties = new Properties();
 
-  /* package-private */
-  static Map<String, String> loadPropertiesFromURL(URL gfSecurityPropertiesUrl) {
-    Map<String, String> propsMap = Collections.emptyMap();
+    if (url == null) {
+      return properties;
+    }
 
-    if (gfSecurityPropertiesUrl != null) {
-      InputStream inputStream = null;
-      try {
-        Properties props = new Properties();
-        inputStream = gfSecurityPropertiesUrl.openStream();
-        props.load(inputStream);
-        if (!props.isEmpty()) {
-          Set<String> jmxSpecificProps = new HashSet<String>();
-          propsMap = new LinkedHashMap<String, String>();
-          Set<Entry<Object, Object>> entrySet = props.entrySet();
-          for (Entry<Object, Object> entry : entrySet) {
-
-            String key = (String) entry.getKey();
-            if (key.endsWith(DistributionConfig.JMX_SSL_PROPS_SUFFIX)) {
-              key =
-                  key.substring(0, key.length() - DistributionConfig.JMX_SSL_PROPS_SUFFIX.length());
-              jmxSpecificProps.add(key);
-
-              propsMap.put(key, (String) entry.getValue());
-            } else if (!jmxSpecificProps.contains(key)) {// Prefer properties ending with "-jmx"
-              // over default SSL props.
-              propsMap.put(key, (String) entry.getValue());
-            }
-          }
-          props.clear();
-          jmxSpecificProps.clear();
-        }
-      } catch (IOException io) {
-        throw new RuntimeException(
-            CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_READ_CONFIG_FROM_0,
-                CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath())),
-            io);
-      } finally {
-        IOUtils.close(inputStream);
-      }
+    try (InputStream inputStream = url.openStream()) {
+      properties.load(inputStream);
+    } catch (IOException io) {
+      throw new RuntimeException(
+          CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_READ_CONFIG_FROM_0,
+              CliUtil.decodeWithDefaultCharSet(url.getPath())),
+          io);
+    }
+
+    return properties;
+  }
+
+  static Properties loadProperties(File propertyFile) {
+    try {
+      return loadProperties(propertyFile.toURI().toURL());
+    } catch (MalformedURLException e) {
+      throw new RuntimeException(
+          CliStrings.format("Failed to load configuration properties from pathname (%1$s)!",
+              propertyFile.getAbsolutePath()),
+          e);
     }
-    return propsMap;
   }
 
-  // Copied from DistributedSystem.java
-  public static URL getFileUrl(String fileName) {
+  /**
+   * try to find the file in the current dir or the user home or the classpath in this order
+   * 
+   * @param fileName the name of the file
+   * @return URL if the file is found, otherwise null
+   */
+  public static URL searchFile(String fileName) {
     File file = new File(fileName);
 
     if (file.exists()) {

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
index 5b289a5..72ccfbb 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java
@@ -17,17 +17,13 @@ package org.apache.geode.management.internal.cli.commands;
 
 import java.io.File;
 import java.net.InetAddress;
-import java.net.MalformedURLException;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 
 import javax.management.MalformedObjectNameException;
 import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
 
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
@@ -47,9 +43,7 @@ import org.apache.geode.internal.util.IOUtils;
 import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.cli.ConverterHint;
 import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.GfshParser;
-import org.apache.geode.management.internal.cli.LogWrapper;
 import org.apache.geode.management.internal.cli.domain.ConnectToLocatorResult;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.InfoResultData;
@@ -100,12 +94,11 @@ public class StartLocatorCommand implements GfshCommand {
           help = CliStrings.START_LOCATOR__PORT__HELP) final Integer port,
       @CliOption(key = CliStrings.START_LOCATOR__DIR,
           help = CliStrings.START_LOCATOR__DIR__HELP) String workingDirectory,
-      @CliOption(key = CliStrings.START_LOCATOR__PROPERTIES,
-          optionContext = ConverterHint.FILE_PATH,
-          help = CliStrings.START_LOCATOR__PROPERTIES__HELP) String gemfirePropertiesPathname,
+      @CliOption(key = CliStrings.START_LOCATOR__PROPERTIES, optionContext = ConverterHint.FILE,
+          help = CliStrings.START_LOCATOR__PROPERTIES__HELP) File gemfirePropertiesFile,
       @CliOption(key = CliStrings.START_LOCATOR__SECURITY_PROPERTIES,
-          optionContext = ConverterHint.FILE_PATH,
-          help = CliStrings.START_LOCATOR__SECURITY_PROPERTIES__HELP) String gemfireSecurityPropertiesPathname,
+          optionContext = ConverterHint.FILE,
+          help = CliStrings.START_LOCATOR__SECURITY_PROPERTIES__HELP) File gemfireSecurityPropertiesFile,
       @CliOption(key = CliStrings.START_LOCATOR__INITIALHEAP,
           help = CliStrings.START_LOCATOR__INITIALHEAP__HELP) final String initialHeap,
       @CliOption(key = CliStrings.START_LOCATOR__MAXHEAP,
@@ -135,23 +128,16 @@ public class StartLocatorCommand implements GfshCommand {
 
       workingDirectory = StartMemberUtils.resolveWorkingDir(workingDirectory, memberName);
 
-      gemfirePropertiesPathname = CliUtil.resolvePathname(gemfirePropertiesPathname);
-
-      if (StringUtils.isNotBlank(gemfirePropertiesPathname)
-          && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) {
+      if (gemfirePropertiesFile != null && !gemfirePropertiesFile.exists()) {
         return ResultBuilder.createUserErrorResult(
             CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, StringUtils.EMPTY,
-                gemfirePropertiesPathname));
+                gemfirePropertiesFile.getAbsolutePath()));
       }
 
-      gemfireSecurityPropertiesPathname =
-          CliUtil.resolvePathname(gemfireSecurityPropertiesPathname);
-
-      if (StringUtils.isNotBlank(gemfireSecurityPropertiesPathname)
-          && !IOUtils.isExistingPathname(gemfireSecurityPropertiesPathname)) {
+      if (gemfireSecurityPropertiesFile != null && !gemfireSecurityPropertiesFile.exists()) {
         return ResultBuilder.createUserErrorResult(
             CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security ",
-                gemfireSecurityPropertiesPathname));
+                gemfireSecurityPropertiesFile.getAbsolutePath()));
       }
 
       File locatorPidFile = new File(workingDirectory, ProcessType.LOCATOR.getPidFileName());
@@ -200,8 +186,8 @@ public class StartLocatorCommand implements GfshCommand {
       LocatorLauncher locatorLauncher = locatorLauncherBuilder.build();
 
       String[] locatorCommandLine = createStartLocatorCommandLine(locatorLauncher,
-          gemfirePropertiesPathname, gemfireSecurityPropertiesPathname, gemfireProperties,
-          classpath, includeSystemClasspath, jvmArgsOpts, initialHeap, maxHeap);
+          gemfirePropertiesFile, gemfireSecurityPropertiesFile, gemfireProperties, classpath,
+          includeSystemClasspath, jvmArgsOpts, initialHeap, maxHeap);
 
       final Process locatorProcess = new ProcessBuilder(locatorCommandLine)
           .directory(new File(locatorLauncher.getWorkingDirectory())).start();
@@ -240,7 +226,7 @@ public class StartLocatorCommand implements GfshCommand {
                 new File(locatorLauncher.getWorkingDirectory()))),
             null);
 
-        locatorState = LocatorLauncher.LocatorState.fromDirectory(workingDirectory, memberName);
+        LocatorLauncher.LocatorState.fromDirectory(workingDirectory, memberName);
         do {
           if (locatorProcess.isAlive()) {
             Gfsh.print(".");
@@ -289,33 +275,39 @@ public class StartLocatorCommand implements GfshCommand {
       if (asyncStart) {
         infoResultData.addLine(
             String.format(CliStrings.ASYNC_PROCESS_LAUNCH_MESSAGE, CliStrings.LOCATOR_TERM_NAME));
+        return ResultBuilder.buildResult(infoResultData);
+      }
+
+      infoResultData.addLine(locatorState.toString());
+      String locatorHostName;
+      InetAddress bindAddr = locatorLauncher.getBindAddress();
+      if (bindAddr != null) {
+        locatorHostName = bindAddr.getCanonicalHostName();
       } else {
-        infoResultData.addLine(locatorState.toString());
-
-        String locatorHostName;
-        InetAddress bindAddr = locatorLauncher.getBindAddress();
-        if (bindAddr != null) {
-          locatorHostName = bindAddr.getCanonicalHostName();
-        } else {
-          locatorHostName = StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(),
-              HostUtils.getLocalHost());
-        }
+        locatorHostName = StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(),
+            HostUtils.getLocalHost());
+      }
 
-        int locatorPort = Integer.parseInt(locatorState.getPort());
+      int locatorPort = Integer.parseInt(locatorState.getPort());
 
-        // AUTO-CONNECT
-        // If the connect succeeds add the connected message to the result,
-        // Else, ask the user to use the "connect" command to connect to the Locator.
-        if (shouldAutoConnect(connect)) {
-          doAutoConnect(locatorHostName, locatorPort, gemfirePropertiesPathname,
-              gemfireSecurityPropertiesPathname, infoResultData);
-        }
-        // Report on the state of the Shared Configuration service if enabled...
-        if (enableSharedConfiguration) {
-          infoResultData.addLine(
-              ClusterConfigurationStatusRetriever.fromLocator(locatorHostName, locatorPort));
-        }
+
+      ConnectCommand connectCommand = new ConnectCommand();
+      Properties configProperties = connectCommand.resolveSslProperties(getGfsh(), false,
+          gemfirePropertiesFile, gemfireSecurityPropertiesFile);
+
+      // AUTO-CONNECT
+      // If the connect succeeds add the connected message to the result,
+      // Else, ask the user to use the "connect" command to connect to the Locator.
+      if (shouldAutoConnect(connect)) {
+        doAutoConnect(locatorHostName, locatorPort, configProperties, infoResultData);
       }
+
+      // Report on the state of the Shared Configuration service if enabled...
+      if (enableSharedConfiguration) {
+        infoResultData.addLine(ClusterConfigurationStatusRetriever.fromLocator(locatorHostName,
+            locatorPort, configProperties));
+      }
+
       return ResultBuilder.buildResult(infoResultData);
     } catch (IllegalArgumentException e) {
       String message = e.getMessage();
@@ -348,38 +340,29 @@ public class StartLocatorCommand implements GfshCommand {
   // With execute option (-e), there could be multiple commands which might presume that a prior
   // "start locator" has formed the connection.
   private boolean shouldAutoConnect(final boolean connect) {
-    return (connect && !(getGfsh() == null || isConnectedAndReady()));
+    return (connect && !isConnectedAndReady());
   }
 
   private void doAutoConnect(final String locatorHostname, final int locatorPort,
-      final String gemfirePropertiesPathname, final String gemfireSecurityPropertiesPathname,
-      final InfoResultData infoResultData) {
+      final Properties configurationProperties, final InfoResultData infoResultData) {
     boolean connectSuccess = false;
     boolean jmxManagerAuthEnabled = false;
     boolean jmxManagerSslEnabled = false;
 
-    Map<String, String> configurationProperties = loadConfigurationProperties(
-        gemfireSecurityPropertiesPathname, loadConfigurationProperties(gemfirePropertiesPathname));
-    Map<String, String> locatorConfigurationProperties = new HashMap<>(configurationProperties);
-
     String responseFailureMessage = null;
 
     for (int attempts = 0; (attempts < 10 && !connectSuccess); attempts++) {
       try {
         ConnectToLocatorResult connectToLocatorResult =
             ConnectCommand.connectToLocator(locatorHostname, locatorPort,
-                ConnectCommand.CONNECT_LOCATOR_TIMEOUT_MS / 4, locatorConfigurationProperties);
+                ConnectCommand.CONNECT_LOCATOR_TIMEOUT_MS / 4, configurationProperties);
 
         ConnectionEndpoint memberEndpoint = connectToLocatorResult.getMemberEndpoint();
 
         jmxManagerSslEnabled = connectToLocatorResult.isJmxManagerSslEnabled();
 
-        if (!jmxManagerSslEnabled) {
-          configurationProperties.clear();
-        }
-
         getGfsh().setOperationInvoker(new JmxOperationInvoker(memberEndpoint.getHost(),
-            memberEndpoint.getPort(), null, null, configurationProperties, null));
+            memberEndpoint.getPort(), configurationProperties));
 
         String shellAndLogMessage = CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS,
             "JMX Manager " + memberEndpoint.toString(false));
@@ -403,16 +386,9 @@ public class StartLocatorCommand implements GfshCommand {
         jmxManagerAuthEnabled = true;
         break; // no need to continue after AuthenticationFailedException
       } catch (SSLException ignore) {
-        if (ignore instanceof SSLHandshakeException) {
-          // try to connect again without SSL since the SSL handshake failed implying a plain text
-          // connection...
-          locatorConfigurationProperties.clear();
-        } else {
-          // another type of SSL error occurred (possibly a configuration issue); pass the buck...
-          getGfsh().logToFile(ignore.getMessage(), ignore);
-          responseFailureMessage = "Check your SSL configuration and try again.";
-          break;
-        }
+        // another type of SSL error occurred (possibly a configuration issue); pass the buck...
+        getGfsh().logToFile(ignore.getMessage(), ignore);
+        responseFailureMessage = "Check your SSL configuration and try again.";
       } catch (Exception ignore) {
         getGfsh().logToFile(ignore.getMessage(), ignore);
         responseFailureMessage = "Failed to connect; unknown cause: " + ignore.getMessage();
@@ -431,30 +407,6 @@ public class StartLocatorCommand implements GfshCommand {
 
   }
 
-  private Map<String, String> loadConfigurationProperties(
-      final String configurationPropertiesPathname) {
-    return loadConfigurationProperties(configurationPropertiesPathname, null);
-  }
-
-  private Map<String, String> loadConfigurationProperties(
-      final String configurationPropertiesPathname, Map<String, String> configurationProperties) {
-    configurationProperties =
-        (configurationProperties != null ? configurationProperties : new HashMap<>());
-
-    if (IOUtils.isExistingPathname(configurationPropertiesPathname)) {
-      try {
-        configurationProperties.putAll(ShellCommands
-            .loadPropertiesFromURL(new File(configurationPropertiesPathname).toURI().toURL()));
-      } catch (MalformedURLException ignore) {
-        LogWrapper.getInstance()
-            .warning(String.format(
-                "Failed to load GemFire configuration properties from pathname (%1$s)!",
-                configurationPropertiesPathname), ignore);
-      }
-    }
-    return configurationProperties;
-  }
-
   private void doOnConnectionFailure(final String locatorHostName, final int locatorPort,
       final boolean jmxManagerAuthEnabled, final boolean jmxManagerSslEnabled,
       final InfoResultData infoResultData) {
@@ -481,7 +433,7 @@ public class StartLocatorCommand implements GfshCommand {
   }
 
   String[] createStartLocatorCommandLine(final LocatorLauncher launcher,
-      final String gemfirePropertiesPathname, final String gemfireSecurityPropertiesPathname,
+      final File gemfirePropertiesFile, final File gemfireSecurityPropertiesFile,
       final Properties gemfireProperties, final String userClasspath,
       final Boolean includeSystemClasspath, final String[] jvmArgsOpts, final String initialHeap,
       final String maxHeap) throws MalformedObjectNameException {
@@ -494,8 +446,8 @@ public class StartLocatorCommand implements GfshCommand {
         .add(getLocatorClasspath(Boolean.TRUE.equals(includeSystemClasspath), userClasspath));
 
     StartMemberUtils.addCurrentLocators(this, commandLine, gemfireProperties);
-    StartMemberUtils.addGemFirePropertyFile(commandLine, gemfirePropertiesPathname);
-    StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesPathname);
+    StartMemberUtils.addGemFirePropertyFile(commandLine, gemfirePropertiesFile);
+    StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesFile);
     StartMemberUtils.addGemFireSystemProperties(commandLine, gemfireProperties);
     StartMemberUtils.addJvmArgumentsAndOptions(commandLine, jvmArgsOpts);
     StartMemberUtils.addInitialHeap(commandLine, initialHeap);


[18/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherTest.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherTest.java
index 46d51e8..23395cc 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherTest.java
@@ -14,253 +14,362 @@
  */
 package org.apache.geode.distributed;
 
+import static java.util.concurrent.TimeUnit.DAYS;
+import static java.util.concurrent.TimeUnit.HOURS;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.distributed.AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.entry;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import java.net.URL;
+import java.util.Properties;
+
 import org.apache.commons.lang.StringUtils;
-import org.apache.geode.test.junit.categories.UnitTest;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
+import org.apache.geode.test.junit.categories.UnitTest;
 
 /**
- * The AbstractLauncherTest class is a test suite of unit tests testing the contract and
- * functionality of the AbstractLauncher class.
- * <p/>
- * 
- * @see org.apache.geode.distributed.AbstractLauncher
- * @see org.junit.Assert
- * @see org.junit.Test
+ * Unit tests for {@link AbstractLauncher}.
+ *
  * @since GemFire 7.0
  */
 @Category(UnitTest.class)
 public class AbstractLauncherTest {
 
-  private AbstractLauncher<?> createAbstractLauncher(final String memberName,
-      final String memberId) {
-    return new FakeServiceLauncher(memberName, memberId);
-  }
-
   @Test
-  public void shouldBeMockable() throws Exception {
+  public void canBeMocked() throws Exception {
     AbstractLauncher mockAbstractLauncher = mock(AbstractLauncher.class);
     mockAbstractLauncher.setDebug(true);
     verify(mockAbstractLauncher, times(1)).setDebug(true);
   }
 
   @Test
-  public void testIsSet() {
-    final Properties properties = new Properties();
+  public void isSetReturnsFalseIfPropertyDoesNotExist() throws Exception {
+    assertThat(AbstractLauncher.isSet(new Properties(), NAME)).isFalse();
+  }
 
-    assertFalse(properties.containsKey(NAME));
-    assertFalse(AbstractLauncher.isSet(properties, NAME));
+  @Test
+  public void isSetReturnsFalseIfPropertyHasEmptyValue() throws Exception {
+    Properties properties = new Properties();
 
     properties.setProperty(NAME, "");
 
-    assertTrue(properties.containsKey(NAME));
-    assertFalse(AbstractLauncher.isSet(properties, NAME));
+    assertThat(AbstractLauncher.isSet(properties, NAME)).isFalse();
+  }
+
+  @Test
+  public void isSetReturnsFalseIfPropertyHasBlankValue() throws Exception {
+    Properties properties = new Properties();
 
     properties.setProperty(NAME, "  ");
 
-    assertTrue(properties.containsKey(NAME));
-    assertFalse(AbstractLauncher.isSet(properties, NAME));
+    assertThat(AbstractLauncher.isSet(properties, NAME)).isFalse();
+  }
+
+  @Test
+  public void isSetReturnsTrueIfPropertyHasRealValue() throws Exception {
+    Properties properties = new Properties();
+
+    properties.setProperty(NAME, "memberOne");
+
+    assertThat(AbstractLauncher.isSet(properties, NAME)).isTrue();
+  }
+
+  @Test
+  public void isSetKeyIsCaseSensitive() throws Exception {
+    Properties properties = new Properties();
 
     properties.setProperty(NAME, "memberOne");
 
-    assertTrue(AbstractLauncher.isSet(properties, NAME));
-    assertFalse(AbstractLauncher.isSet(properties, "NaMe"));
+    assertThat(AbstractLauncher.isSet(properties, "NaMe")).isFalse();
   }
 
   @Test
-  public void testLoadGemFirePropertiesWithNullURL() {
-    final Properties properties = AbstractLauncher.loadGemFireProperties(null);
-    assertNotNull(properties);
-    assertTrue(properties.isEmpty());
+  public void loadGemFirePropertiesWithNullURLReturnsEmptyProperties() throws Exception {
+    URL nullUrl = null;
+
+    Properties properties = AbstractLauncher.loadGemFireProperties(nullUrl);
+
+    assertThat(properties).isNotNull().isEmpty();
   }
 
   @Test
-  public void testLoadGemFirePropertiesWithNonExistingURL() throws MalformedURLException {
-    final Properties properties = AbstractLauncher
-        .loadGemFireProperties(new URL("file:///path/to/non_existing/gemfire.properties"));
-    assertNotNull(properties);
-    assertTrue(properties.isEmpty());
+  public void loadGemFirePropertiesWithNonExistingURLReturnsEmptyProperties() throws Exception {
+    URL nonExistingUrl = new URL("file:///path/to/non_existing/gemfire.properties");
+
+    Properties properties = AbstractLauncher.loadGemFireProperties(nonExistingUrl);
+
+    assertThat(properties).isNotNull().isEmpty();
   }
 
   @Test
-  public void testGetDistributedSystemProperties() {
+  public void getDistributedSystemPropertiesContainsMemberNameAsName() throws Exception {
     AbstractLauncher<?> launcher = createAbstractLauncher("memberOne", "1");
 
-    assertNotNull(launcher);
-    assertEquals("1", launcher.getMemberId());
-    assertEquals("memberOne", launcher.getMemberName());
+    Properties properties = launcher.getDistributedSystemProperties();
+
+    assertThat(properties).containsExactly(entry(NAME, "memberOne"));
+  }
+
+  @Test
+  public void getDistributedSystemPropertiesIsEmptyWhenMemberNameIsNull() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, "22");
 
-    Properties distributedSystemProperties = launcher.getDistributedSystemProperties();
+    Properties properties = launcher.getDistributedSystemProperties();
 
-    assertNotNull(distributedSystemProperties);
-    assertTrue(distributedSystemProperties.containsKey(NAME));
-    assertEquals("memberOne", distributedSystemProperties.getProperty(NAME));
+    assertThat(properties).isEmpty();
+  }
 
-    launcher = createAbstractLauncher(null, "22");
+  @Test
+  public void getDistributedSystemPropertiesIsEmptyWhenMemberNameIsEmpty() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(StringUtils.EMPTY, "333");
 
-    assertNotNull(launcher);
-    assertEquals("22", launcher.getMemberId());
-    assertNull(launcher.getMemberName());
+    Properties properties = launcher.getDistributedSystemProperties();
 
-    distributedSystemProperties = launcher.getDistributedSystemProperties();
+    assertThat(properties).isEmpty();
+  }
 
-    assertNotNull(distributedSystemProperties);
-    assertFalse(distributedSystemProperties.containsKey(NAME));
+  @Test
+  public void getDistributedSystemPropertiesIsEmptyWhenMemberNameIsBlank() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher("  ", "4444");
 
-    launcher = createAbstractLauncher(StringUtils.EMPTY, "333");
+    Properties properties = launcher.getDistributedSystemProperties();
 
-    assertNotNull(launcher);
-    assertEquals("333", launcher.getMemberId());
-    assertEquals(StringUtils.EMPTY, launcher.getMemberName());
+    assertThat(properties).isEmpty();
+  }
 
-    distributedSystemProperties = launcher.getDistributedSystemProperties();
+  @Test
+  public void getDistributedSystemPropertiesIncludesDefaults() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher("TestMember", "123");
+    Properties defaults = new Properties();
+    defaults.setProperty("testKey", "testValue");
 
-    assertNotNull(distributedSystemProperties);
-    assertFalse(distributedSystemProperties.containsKey(NAME));
+    Properties properties = launcher.getDistributedSystemProperties(defaults);
+
+    assertThat(properties.getProperty(NAME)).isEqualTo(launcher.getMemberName());
+    assertThat(properties.getProperty("testKey")).isEqualTo("testValue");
+  }
 
-    launcher = createAbstractLauncher("  ", "4444");
+  @Test
+  public void getMemberNameReturnsValue() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher("memberOne", null);
 
-    assertNotNull(launcher);
-    assertEquals("4444", launcher.getMemberId());
-    assertEquals("  ", launcher.getMemberName());
+    assertThat(launcher.getMemberName()).isEqualTo("memberOne");
+  }
 
-    distributedSystemProperties = launcher.getDistributedSystemProperties();
+  @Test
+  public void getMemberNameReturnsEmptyIfEmpty() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(StringUtils.EMPTY, null);
 
-    assertNotNull(distributedSystemProperties);
-    assertFalse(distributedSystemProperties.containsKey(NAME));
+    assertThat(launcher.getMemberName()).isEqualTo(StringUtils.EMPTY);
   }
 
   @Test
-  public void testGetDistributedSystemPropertiesWithDefaults() {
-    AbstractLauncher<?> launcher = createAbstractLauncher("TestMember", "123");
+  public void getMemberNameReturnsBlankIfBlank() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(" ", null);
 
-    assertNotNull(launcher);
-    assertEquals("123", launcher.getMemberId());
-    assertEquals("TestMember", launcher.getMemberName());
+    assertThat(launcher.getMemberName()).isEqualTo(" ");
+  }
 
-    Properties defaults = new Properties();
+  @Test
+  public void getMemberNameReturnsSameNumberOfBlanks() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher("   ", null);
 
-    defaults.setProperty("testKey", "testValue");
+    assertThat(launcher.getMemberName()).isEqualTo("   ");
+  }
+
+  @Test
+  public void getMemberIdReturnsValue() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, "123");
+
+    assertThat(launcher.getMemberId()).isEqualTo("123");
+  }
+
+  @Test
+  public void getMemberIdReturnsNullIfNull() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, null);
+
+    assertThat(launcher.getMemberId()).isNull();
+  }
+
+  @Test
+  public void getMemberIdReturnsEmptyIfEmpty() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, StringUtils.EMPTY);
+
+    assertThat(launcher.getMemberId()).isEqualTo(StringUtils.EMPTY);
+  }
 
-    Properties distributedSystemProperties = launcher.getDistributedSystemProperties(defaults);
+  @Test
+  public void getMemberIdReturnsBlankIfBlank() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, " ");
 
-    assertNotNull(distributedSystemProperties);
-    assertEquals(launcher.getMemberName(), distributedSystemProperties.getProperty(NAME));
-    assertEquals("testValue", distributedSystemProperties.getProperty("testKey"));
+    assertThat(launcher.getMemberId()).isEqualTo(" ");
   }
 
   @Test
-  public void testGetMember() {
+  public void getMemberIdReturnsSameNumberOfBlanks() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, "   ");
+
+    assertThat(launcher.getMemberId()).isEqualTo("   ");
+  }
+
+  @Test
+  public void getMemberPrefersMemberNameOverMemberId() throws Exception {
     AbstractLauncher<?> launcher = createAbstractLauncher("memberOne", "123");
 
-    assertNotNull(launcher);
-    assertEquals("123", launcher.getMemberId());
-    assertEquals("memberOne", launcher.getMemberName());
-    assertEquals("memberOne", launcher.getMember());
-
-    launcher = createAbstractLauncher(null, "123");
-
-    assertNotNull(launcher);
-    assertEquals("123", launcher.getMemberId());
-    assertNull(launcher.getMemberName());
-    assertEquals("123", launcher.getMember());
-
-    launcher = createAbstractLauncher(StringUtils.EMPTY, "123");
-
-    assertNotNull(launcher);
-    assertEquals("123", launcher.getMemberId());
-    assertEquals(StringUtils.EMPTY, launcher.getMemberName());
-    assertEquals("123", launcher.getMember());
-
-    launcher = createAbstractLauncher(" ", "123");
-
-    assertNotNull(launcher);
-    assertEquals("123", launcher.getMemberId());
-    assertEquals(" ", launcher.getMemberName());
-    assertEquals("123", launcher.getMember());
-
-    launcher = createAbstractLauncher(null, StringUtils.EMPTY);
-
-    assertNotNull(launcher);
-    assertEquals(StringUtils.EMPTY, launcher.getMemberId());
-    assertNull(launcher.getMemberName());
-    assertNull(launcher.getMember());
-
-    launcher = createAbstractLauncher(null, " ");
-
-    assertNotNull(launcher);
-    assertEquals(" ", launcher.getMemberId());
-    assertNull(launcher.getMemberName());
-    assertNull(launcher.getMember());
-  }
-
-  @Test
-  public void testAbstractLauncherServiceStateToDaysHoursMinutesSeconds() {
-    assertEquals("", AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(null));
-    assertEquals("0 seconds", AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(0l));
-    assertEquals("1 second", AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(1000l));
-    assertEquals("1 second", AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(1999l));
-    assertEquals("2 seconds", AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(2001l));
-    assertEquals("45 seconds", AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(45000l));
-    assertEquals("1 minute 0 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 1000l));
-    assertEquals("1 minute 1 second",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(61 * 1000l));
-    assertEquals("1 minute 30 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(90 * 1000l));
-    assertEquals("2 minutes 0 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(120 * 1000l));
-    assertEquals("2 minutes 1 second",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(121 * 1000l));
-    assertEquals("2 minutes 15 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(135 * 1000l));
-    assertEquals("1 hour 0 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 60 * 1000l));
-    assertEquals("1 hour 1 second",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 60 * 1000l + 1000l));
-    assertEquals("1 hour 15 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 60 * 1000l + 15000l));
-    assertEquals("1 hour 1 minute 0 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 61 * 1000l));
-    assertEquals("1 hour 1 minute 1 second",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 61 * 1000l + 1000l));
-    assertEquals("1 hour 1 minute 45 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 61 * 1000l + 45000l));
-    assertEquals("1 hour 2 minutes 0 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 62 * 1000l));
-    assertEquals("1 hour 5 minutes 1 second",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 65 * 1000l + 1000l));
-    assertEquals("1 hour 5 minutes 10 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 65 * 1000l + 10000l));
-    assertEquals("1 hour 59 minutes 11 seconds",
-        AbstractLauncher.ServiceState.toDaysHoursMinutesSeconds(60 * 119 * 1000l + 11000l));
-    assertEquals("1 day 1 hour 1 minute 1 second",
-        AbstractLauncher.ServiceState
-            .toDaysHoursMinutesSeconds(TimeUnit.DAYS.toMillis(1) + TimeUnit.HOURS.toMillis(1)
-                + TimeUnit.MINUTES.toMillis(1) + TimeUnit.SECONDS.toMillis(1)));
-    assertEquals("1 day 5 hours 15 minutes 45 seconds",
-        AbstractLauncher.ServiceState
-            .toDaysHoursMinutesSeconds(TimeUnit.DAYS.toMillis(1) + TimeUnit.HOURS.toMillis(5)
-                + TimeUnit.MINUTES.toMillis(15) + TimeUnit.SECONDS.toMillis(45)));
-    assertEquals("2 days 1 hour 30 minutes 1 second",
-        AbstractLauncher.ServiceState
-            .toDaysHoursMinutesSeconds(TimeUnit.DAYS.toMillis(2) + TimeUnit.HOURS.toMillis(1)
-                + TimeUnit.MINUTES.toMillis(30) + TimeUnit.SECONDS.toMillis(1)));
+    assertThat(launcher.getMember()).isEqualTo("memberOne").isEqualTo(launcher.getMemberName());
+  }
+
+  @Test
+  public void getMemberReturnsMemberIdIfMemberNameIsNull() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, "123");
+
+    assertThat(launcher.getMember()).isEqualTo("123").isEqualTo(launcher.getMemberId());
+  }
+
+  @Test
+  public void getMemberReturnsMemberIdIfMemberNameIsEmpty() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(StringUtils.EMPTY, "123");
+
+    assertThat(launcher.getMember()).isEqualTo("123").isEqualTo(launcher.getMemberId());
+  }
+
+  @Test
+  public void getMemberReturnsMemberIdIfMemberNameIsBlank() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(" ", "123");
+
+    assertThat(launcher.getMember()).isEqualTo("123").isEqualTo(launcher.getMemberId());
+  }
+
+  @Test
+  public void getMemberReturnsNullIfMemberIdIsNull() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, null);
+
+    assertThat(launcher.getMember()).isNull();
+  }
+
+  @Test
+  public void getMemberReturnNullIfMemberIdIsEmpty() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, StringUtils.EMPTY);
+
+    assertThat(launcher.getMember()).isNull();
+  }
+
+  @Test
+  public void getMemberReturnNullIfMemberIdIsBlank() throws Exception {
+    AbstractLauncher<?> launcher = createAbstractLauncher(null, " ");
+
+    assertThat(launcher.getMember()).isNull();
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_null_returnsEmptyString() throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(null)).isEqualTo("");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_milliseconds_returnsSecondsString() throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(MILLISECONDS.toMillis(0))).isEqualTo("0 seconds");
+    assertThat(toDaysHoursMinutesSeconds(MILLISECONDS.toMillis(999))).isEqualTo("0 seconds");
+    assertThat(toDaysHoursMinutesSeconds(MILLISECONDS.toMillis(1000))).isEqualTo("1 second");
+    assertThat(toDaysHoursMinutesSeconds(MILLISECONDS.toMillis(1999))).isEqualTo("1 second");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_seconds_returnsSecondsString() throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(SECONDS.toMillis(0))).isEqualTo("0 seconds");
+    assertThat(toDaysHoursMinutesSeconds(SECONDS.toMillis(1))).isEqualTo("1 second");
+    assertThat(toDaysHoursMinutesSeconds(SECONDS.toMillis(2))).isEqualTo("2 seconds");
+    assertThat(toDaysHoursMinutesSeconds(SECONDS.toMillis(45))).isEqualTo("45 seconds");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_minutes_returnsMinutesAndSecondsString() throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(MINUTES.toMillis(1))).isEqualTo("1 minute 0 seconds");
+    assertThat(toDaysHoursMinutesSeconds(MINUTES.toMillis(2))).isEqualTo("2 minutes 0 seconds");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_minutesAndSeconds_returnsMinutesAndSecondsString()
+      throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(MINUTES.toMillis(1) + SECONDS.toMillis(1)))
+        .isEqualTo("1 minute 1 second");
+    assertThat(toDaysHoursMinutesSeconds(MINUTES.toMillis(1) + SECONDS.toMillis(30)))
+        .isEqualTo("1 minute 30 seconds");
+    assertThat(toDaysHoursMinutesSeconds(MINUTES.toMillis(2) + SECONDS.toMillis(1)))
+        .isEqualTo("2 minutes 1 second");
+    assertThat(toDaysHoursMinutesSeconds(MINUTES.toMillis(2) + SECONDS.toMillis(15)))
+        .isEqualTo("2 minutes 15 seconds");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_hours_returnsHoursAndSecondsString() throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(HOURS.toMillis(1))).isEqualTo("1 hour 0 seconds");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_hoursAndSeconds_returnsHoursAndSecondsString()
+      throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(HOURS.toMillis(1) + SECONDS.toMillis(1)))
+        .isEqualTo("1 hour 1 second");
+    assertThat(toDaysHoursMinutesSeconds(HOURS.toMillis(1) + SECONDS.toMillis(15)))
+        .isEqualTo("1 hour 15 seconds");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_hoursAndMinutes_returnsHoursAndMinutesAndSecondsString()
+      throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(HOURS.toMillis(1) + MINUTES.toMillis(1)))
+        .isEqualTo("1 hour 1 minute 0 seconds");
+    assertThat(toDaysHoursMinutesSeconds(HOURS.toMillis(1) + MINUTES.toMillis(2)))
+        .isEqualTo("1 hour 2 minutes 0 seconds");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_hoursAndMinutesAndSeconds_returnsHoursAndMinutesAndSecondsString()
+      throws Exception {
+    assertThat(
+        toDaysHoursMinutesSeconds(HOURS.toMillis(1) + MINUTES.toMillis(1) + SECONDS.toMillis(1)))
+            .isEqualTo("1 hour 1 minute 1 second");
+    assertThat(
+        toDaysHoursMinutesSeconds(HOURS.toMillis(1) + MINUTES.toMillis(1) + SECONDS.toMillis(45)))
+            .isEqualTo("1 hour 1 minute 45 seconds");
+    assertThat(
+        toDaysHoursMinutesSeconds(HOURS.toMillis(1) + MINUTES.toMillis(5) + SECONDS.toMillis(1)))
+            .isEqualTo("1 hour 5 minutes 1 second");
+    assertThat(
+        toDaysHoursMinutesSeconds(HOURS.toMillis(1) + MINUTES.toMillis(5) + SECONDS.toMillis(10)))
+            .isEqualTo("1 hour 5 minutes 10 seconds");
+    assertThat(
+        toDaysHoursMinutesSeconds(HOURS.toMillis(1) + MINUTES.toMillis(59) + SECONDS.toMillis(11)))
+            .isEqualTo("1 hour 59 minutes 11 seconds");
+  }
+
+  @Test
+  public void toDaysHoursMinutesSeconds_daysAndHoursAndMinutesAndSeconds_returnsDaysAndHoursAndMinutesAndSecondsString()
+      throws Exception {
+    assertThat(toDaysHoursMinutesSeconds(
+        DAYS.toMillis(1) + HOURS.toMillis(1) + MINUTES.toMillis(1) + SECONDS.toMillis(1)))
+            .isEqualTo("1 day 1 hour 1 minute 1 second");
+    assertThat(toDaysHoursMinutesSeconds(
+        DAYS.toMillis(1) + HOURS.toMillis(5) + MINUTES.toMillis(15) + SECONDS.toMillis(45)))
+            .isEqualTo("1 day 5 hours 15 minutes 45 seconds");
+    assertThat(toDaysHoursMinutesSeconds(
+        DAYS.toMillis(2) + HOURS.toMillis(1) + MINUTES.toMillis(30) + SECONDS.toMillis(1)))
+            .isEqualTo("2 days 1 hour 30 minutes 1 second");
+  }
+
+  private AbstractLauncher<?> createAbstractLauncher(final String memberName,
+      final String memberId) {
+    return new FakeServiceLauncher(memberName, memberId);
   }
 
   private static class FakeServiceLauncher extends AbstractLauncher<String> {
@@ -303,5 +412,4 @@ public class AbstractLauncherTest {
       throw new UnsupportedOperationException("Not Implemented!");
     }
   }
-
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherIntegrationTestCase.java
deleted file mode 100755
index 0908b74..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherIntegrationTestCase.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.concurrent.Callable;
-import java.util.function.IntSupplier;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.ErrorCollector;
-import org.junit.rules.TemporaryFolder;
-
-import org.apache.geode.distributed.AbstractLauncher.Status;
-import org.apache.geode.distributed.LocatorLauncher.Builder;
-import org.apache.geode.distributed.LocatorLauncher.LocatorState;
-import org.apache.geode.distributed.internal.ClusterConfigurationService;
-import org.apache.geode.internal.AvailablePortHelper;
-import org.apache.geode.internal.DistributionLocator;
-import org.junit.runners.Parameterized;
-
-/**
- * @since GemFire 8.0
- */
-public abstract class AbstractLocatorLauncherIntegrationTestCase
-    extends AbstractLauncherIntegrationTestCase {
-
-  @Parameterized.Parameters
-  public static Collection<Object> data() {
-    return Arrays.asList(new Object[] {(IntSupplier) () -> 0,
-        (IntSupplier) () -> AvailablePortHelper.getRandomAvailableTCPPort()});
-  }
-
-  @Parameterized.Parameter
-  public IntSupplier portSupplier;
-
-  protected volatile int locatorPort;
-
-  protected volatile LocatorLauncher launcher;
-  protected volatile String workingDirectory;
-  protected volatile String clusterConfigDirectory;
-
-  @Rule
-  public ErrorCollector errorCollector = new ErrorCollector();
-
-  @Rule
-  public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
-  @Before
-  public final void setUpAbstractLocatorLauncherIntegrationTestCase() throws Exception {
-    this.locatorPort = portSupplier.getAsInt();
-    System.setProperty(DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY,
-        String.valueOf(this.locatorPort));
-    this.workingDirectory = this.temporaryFolder.getRoot().getCanonicalPath();
-    this.clusterConfigDirectory = this.temporaryFolder
-        .newFolder(ClusterConfigurationService.CLUSTER_CONFIG_DISK_DIR_PREFIX + getUniqueName())
-        .getCanonicalPath();
-  }
-
-  @After
-  public final void tearDownAbstractLocatorLauncherIntegrationTestCase() throws Exception {
-    this.locatorPort = 0;
-    if (this.launcher != null) {
-      this.launcher.stop();
-      this.launcher = null;
-    }
-  }
-
-  /**
-   * Override if needed
-   */
-  protected Status getExpectedStopStatusForNotRunning() {
-    return Status.NOT_RESPONDING;
-  }
-
-  protected void waitForLocatorToStart(final LocatorLauncher launcher, int timeout, int interval,
-      boolean throwOnTimeout) throws Exception {
-    assertEventuallyTrue("waiting for process to start: " + launcher.status(),
-        new Callable<Boolean>() {
-          @Override
-          public Boolean call() throws Exception {
-            try {
-              final LocatorState LocatorState = launcher.status();
-              return (LocatorState != null && Status.ONLINE.equals(LocatorState.getStatus()));
-            } catch (RuntimeException e) {
-              return false;
-            }
-          }
-        }, timeout, interval);
-  }
-
-  protected void waitForLocatorToStart(final LocatorLauncher launcher, int timeout,
-      boolean throwOnTimeout) throws Exception {
-    waitForLocatorToStart(launcher, timeout, INTERVAL_MILLISECONDS, throwOnTimeout);
-  }
-
-  protected void waitForLocatorToStart(final LocatorLauncher launcher, boolean throwOnTimeout)
-      throws Exception {
-    waitForLocatorToStart(launcher, TIMEOUT_MILLISECONDS, INTERVAL_MILLISECONDS, throwOnTimeout);
-  }
-
-  protected void waitForLocatorToStart(final LocatorLauncher launcher) throws Exception {
-    waitForLocatorToStart(launcher, TIMEOUT_MILLISECONDS, INTERVAL_MILLISECONDS, true);
-  }
-
-  protected static void waitForLocatorToStart(int port, int timeout, int interval,
-      boolean throwOnTimeout) throws Exception {
-    final LocatorLauncher locatorLauncher = new Builder().setPort(port).build();
-    assertEventuallyTrue("Waiting for Locator in other process to start.", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        try {
-          final LocatorState locatorState = locatorLauncher.status();
-          return (locatorState != null && Status.ONLINE.equals(locatorState.getStatus()));
-        } catch (RuntimeException e) {
-          return false;
-        }
-      }
-    }, timeout, interval);
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherRemoteIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherRemoteIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherRemoteIntegrationTestCase.java
deleted file mode 100644
index 4117d25..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLocatorLauncherRemoteIntegrationTestCase.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.junit.After;
-import org.junit.Before;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public abstract class AbstractLocatorLauncherRemoteIntegrationTestCase
-    extends AbstractLocatorLauncherIntegrationTestCase {
-
-  protected volatile Process process;
-  protected volatile ProcessStreamReader processOutReader;
-  protected volatile ProcessStreamReader processErrReader;
-
-  @Before
-  public final void setUpAbstractLocatorLauncherRemoteIntegrationTestCase() throws Exception {}
-
-  @After
-  public final void tearDownAbstractLocatorLauncherRemoteIntegrationTestCase() throws Exception {
-    if (this.process != null) {
-      this.process.destroy();
-      this.process = null;
-    }
-    if (this.processOutReader != null && this.processOutReader.isRunning()) {
-      this.processOutReader.stop();
-    }
-    if (this.processErrReader != null && this.processErrReader.isRunning()) {
-      this.processErrReader.stop();
-    }
-  }
-
-  /**
-   * Override as needed.
-   */
-  protected List<String> getJvmArguments() {
-    final List<String> jvmArguments = new ArrayList<String>();
-    jvmArguments.add("-D" + DistributionConfig.GEMFIRE_PREFIX + "log-level=config");
-    return jvmArguments;
-  }
-
-  /**
-   * Remove final if a test needs to override.
-   */
-  protected AbstractLauncher.Status getExpectedStopStatusForNotRunning() {
-    return AbstractLauncher.Status.NOT_RESPONDING;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherIntegrationTestCase.java
deleted file mode 100755
index 0e52dfc..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherIntegrationTestCase.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import org.apache.geode.distributed.AbstractLauncher.Status;
-import org.apache.geode.distributed.ServerLauncher.ServerState;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.AvailablePortHelper;
-import org.apache.geode.internal.cache.AbstractCacheServer;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.ErrorCollector;
-import org.junit.rules.TemporaryFolder;
-
-import java.util.concurrent.Callable;
-
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * @since GemFire 8.0
- */
-public abstract class AbstractServerLauncherIntegrationTestCase
-    extends AbstractLauncherIntegrationTestCase {
-
-  protected volatile int serverPort;
-  protected volatile ServerLauncher launcher;
-  protected volatile String workingDirectory;
-
-  @Rule
-  public ErrorCollector errorCollector = new ErrorCollector();
-
-  @Rule
-  public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
-  @Before
-  public final void setUpServerLauncherTest() throws Exception {
-    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + MCAST_PORT, Integer.toString(0));
-    final int port = AvailablePortHelper.getRandomAvailableTCPPort();
-    System.setProperty(AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY,
-        String.valueOf(port));
-    this.serverPort = port;
-    this.workingDirectory = this.temporaryFolder.getRoot().getCanonicalPath();
-  }
-
-  @After
-  public final void tearDownServerLauncherTest() throws Exception {
-    this.serverPort = 0;
-    if (this.launcher != null) {
-      this.launcher.stop();
-      this.launcher = null;
-    }
-  }
-
-  protected void waitForServerToStart(final ServerLauncher launcher, int timeout, int interval,
-      boolean throwOnTimeout) throws Exception {
-    assertEventuallyTrue("waiting for local Server to start: " + launcher.status(),
-        new Callable<Boolean>() {
-          @Override
-          public Boolean call() throws Exception {
-            try {
-              final ServerState serverState = launcher.status();
-              assertNotNull(serverState);
-              return Status.ONLINE.equals(serverState.getStatus());
-            } catch (RuntimeException e) {
-              return false;
-            }
-          }
-        }, timeout, interval);
-  }
-
-  protected void waitForServerToStart(final ServerLauncher launcher, boolean throwOnTimeout)
-      throws Exception {
-    waitForServerToStart(launcher, TIMEOUT_MILLISECONDS, INTERVAL_MILLISECONDS, throwOnTimeout);
-  }
-
-  protected void waitForServerToStart(final ServerLauncher launcher, int timeout,
-      boolean throwOnTimeout) throws Exception {
-    waitForServerToStart(launcher, timeout, INTERVAL_MILLISECONDS, throwOnTimeout);
-  }
-
-  protected void waitForServerToStart(final ServerLauncher launcher) throws Exception {
-    waitForServerToStart(launcher, TIMEOUT_MILLISECONDS, INTERVAL_MILLISECONDS, true);
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherRemoteIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherRemoteIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherRemoteIntegrationTestCase.java
deleted file mode 100644
index b50b77a..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractServerLauncherRemoteIntegrationTestCase.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.junit.After;
-import org.junit.Before;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-
-public abstract class AbstractServerLauncherRemoteIntegrationTestCase
-    extends AbstractServerLauncherIntegrationTestCase {
-
-  protected volatile Process process;
-  protected volatile ProcessStreamReader processOutReader;
-  protected volatile ProcessStreamReader processErrReader;
-
-  @Before
-  public final void setUpAbstractServerLauncherRemoteIntegrationTestCase() throws Exception {}
-
-  @After
-  public final void tearDownAbstractServerLauncherRemoteIntegrationTestCase() throws Exception {
-    if (this.process != null) {
-      this.process.destroy();
-      this.process = null;
-    }
-    if (this.processOutReader != null && this.processOutReader.isRunning()) {
-      this.processOutReader.stop();
-    }
-    if (this.processErrReader != null && this.processErrReader.isRunning()) {
-      this.processErrReader.stop();
-    }
-  }
-
-  /**
-   * Override as needed.
-   */
-  protected List<String> getJvmArguments() {
-    final List<String> jvmArguments = new ArrayList<String>();
-    jvmArguments.add("-D" + DistributionConfig.GEMFIRE_PREFIX + "log-level=config");
-    return jvmArguments;
-  }
-
-  /**
-   * Remove final if a test needs to override.
-   */
-  protected AbstractLauncher.Status getExpectedStopStatusForNotRunning() {
-    return AbstractLauncher.Status.NOT_RESPONDING;
-  }
-
-  protected void waitForServerToStart() throws Exception {
-    assertEventuallyTrue("waiting for local Server to start: " + launcher.status(),
-        new Callable<Boolean>() {
-          @Override
-          public Boolean call() throws Exception {
-            try {
-              assertNotNull(process);
-              try {
-                final int value = process.exitValue();
-                fail("Process has died with exit value " + value
-                    + " while waiting for it to start.");
-              } catch (IllegalThreadStateException e) {
-                // expected
-              }
-              final ServerLauncher.ServerState serverState = launcher.status();
-              assertNotNull(serverState);
-              logger.info("serverState: " + serverState);
-              return AbstractLauncher.Status.ONLINE.equals(serverState.getStatus());
-            } catch (RuntimeException e) {
-              logger.error(e, e);
-              return false;
-            }
-          }
-        }, TIMEOUT_MILLISECONDS, INTERVAL_MILLISECONDS);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LauncherIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LauncherIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/LauncherIntegrationTestCase.java
new file mode 100755
index 0000000..409a96d
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LauncherIntegrationTestCase.java
@@ -0,0 +1,314 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.internal.AvailablePort.SOCKET;
+import static org.apache.geode.internal.AvailablePort.isPortAvailable;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.management.ManagementFactory;
+import java.net.ServerSocket;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.commons.lang.StringUtils;
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.internal.net.SocketCreatorFactory;
+import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
+import org.apache.geode.internal.process.ProcessType;
+import org.apache.geode.internal.process.lang.AvailablePid;
+import org.apache.geode.test.dunit.IgnoredException;
+
+/**
+ * Abstract base class for integration tests of both {@link LocatorLauncher} and
+ * {@link ServerLauncher}.
+ *
+ * @since GemFire 8.0
+ */
+public abstract class LauncherIntegrationTestCase {
+
+  private static final int PREFERRED_FAKE_PID = 42;
+
+  private static final String EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED =
+      "MBean Not Registered In GemFire Domain";
+
+  protected volatile int localPid;
+  protected volatile int fakePid;
+  private volatile ServerSocket socket;
+  private IgnoredException ignoredException;
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @Before
+  public void setUpAbstractLauncherIntegrationTestCase() throws Exception {
+    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + MCAST_PORT, Integer.toString(0));
+    ignoredException =
+        IgnoredException.addIgnoredException(EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED);
+    localPid = identifyPid();
+    fakePid = new AvailablePid().findAvailablePid(PREFERRED_FAKE_PID);
+  }
+
+  @After
+  public void tearDownAbstractLauncherIntegrationTestCase() throws Exception {
+    ignoredException.remove();
+    if (socket != null) {
+      socket.close();
+    }
+  }
+
+  protected abstract ProcessType getProcessType();
+
+  protected void assertDeletionOf(final File file) {
+    await().until(() -> assertThat(file).doesNotExist());
+  }
+
+  protected void assertThatServerPortIsFree(final int serverPort) {
+    assertThatPortIsFree(serverPort);
+  }
+
+  protected void assertThatServerPortIsInUse(final int serverPort) {
+    assertThatPortIsInUse(serverPort);
+  }
+
+  protected void assertThatServerPortIsInUseBySocket(final int serverPort) {
+    assertThatPortIsInUseBySocket(serverPort);
+  }
+
+  protected File givenControlFile(final String name) {
+    try {
+      File file = new File(getWorkingDirectory(), name);
+      assertThat(file.createNewFile()).isTrue();
+      assertThat(file).exists();
+      return file;
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected File givenEmptyPidFile() {
+    return givenPidFile(null);
+  }
+
+  protected void givenEmptyWorkingDirectory() {
+    assertThat(getWorkingDirectory().listFiles()).hasSize(0);
+  }
+
+  protected void givenLocatorPortInUse(final int locatorPort) {
+    givenPortInUse(locatorPort);
+  }
+
+  protected File givenPidFile(final Object content) {
+    try {
+      File file = new File(getWorkingDirectory(), getProcessType().getPidFileName());
+      FileWriter writer = new FileWriter(file);
+      writer.write(String.valueOf(content));
+      writer.write("\n");
+      writer.flush();
+      writer.close();
+      assertTrue(file.exists());
+      return file;
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected void givenServerPortIsFree(final int serverPort) {
+    assertThatPortIsFree(serverPort);
+  }
+
+  protected void givenServerPortInUse(final int serverPort) {
+    givenPortInUse(serverPort);
+  }
+
+  protected ConditionFactory await() {
+    return Awaitility.await().atMost(2, MINUTES);
+  }
+
+  protected InputListener createExpectedListener(final String name, final String expected,
+      final AtomicBoolean atomic) {
+    return new InputListener() {
+      @Override
+      public void notifyInputLine(String line) {
+        if (line.contains(expected)) {
+          atomic.set(true);
+        }
+      }
+
+      @Override
+      public String toString() {
+        return name;
+      }
+    };
+  }
+
+  protected void disconnectFromDS() {
+    InternalDistributedSystem ids = InternalDistributedSystem.getConnectedInstance();
+    if (ids != null) {
+      ids.disconnect();
+    }
+  }
+
+  public String getClassPath() {
+    // alternative: ManagementFactory.getRuntimeMXBean().getClassPath()
+    return System.getProperty("java.class.path");
+  }
+
+  public String getJavaPath() {
+    try {
+      return new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected List<String> getJvmArguments() {
+    return ManagementFactory.getRuntimeMXBean().getInputArguments();
+  }
+
+  protected int getLocatorPid() {
+    return readPidFileWithValidation();
+  }
+
+  protected File getLogFile() {
+    return new File(getWorkingDirectory(), getUniqueName() + ".log");
+  }
+
+  protected String getLogFilePath() {
+    try {
+      return getLogFile().getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected File getPidFile() {
+    return new File(getWorkingDirectory(), getProcessType().getPidFileName());
+  }
+
+  protected String getUniqueName() {
+    return getClass().getSimpleName() + "_" + testName.getMethodName();
+  }
+
+  protected int getServerPid() {
+    return readPidFileWithValidation();
+  }
+
+  protected String getStatusFileName() {
+    return getProcessType().getStatusFileName();
+  }
+
+  protected String getStatusRequestFileName() {
+    return getProcessType().getStatusRequestFileName();
+  }
+
+  protected String getStopRequestFileName() {
+    return getProcessType().getStopRequestFileName();
+  }
+
+  protected File getWorkingDirectory() {
+    return temporaryFolder.getRoot();
+  }
+
+  protected String getWorkingDirectoryPath() {
+    try {
+      return getWorkingDirectory().getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected int readPidFile() {
+    return readPidFile(getPidFile());
+  }
+
+  private void assertThatPortIsFree(final int port) {
+    assertThat(isPortAvailable(port, SOCKET)).isTrue();
+  }
+
+  private void assertThatPortIsInUse(final int port) {
+    assertThat(isPortAvailable(port, SOCKET)).isFalse();
+  }
+
+  private void assertThatPortIsInUseBySocket(final int port) {
+    assertThat(socket.isBound()).isTrue();
+    assertThat(socket.isClosed()).isFalse();
+    assertThat(socket.getLocalPort()).isEqualTo(port);
+    assertThatServerPortIsInUse(port);
+  }
+
+  private void delete(final File file) {
+    assertThat(file.delete()).isTrue();
+  }
+
+  private void givenPortInUse(final int port) {
+    try {
+      socket = SocketCreatorFactory
+          .createNonDefaultInstance(false, false, null, null, System.getProperties())
+          .createServerSocket(port, 50, null, -1);
+      assertThat(socket.isBound()).isTrue();
+      assertThat(socket.isClosed()).isFalse();
+      assertThat(isPortAvailable(port, SOCKET)).isFalse();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private int readPidFile(final File pidFile) {
+    try {
+      assertTrue(pidFile.exists());
+      try (BufferedReader reader = new BufferedReader(new FileReader(pidFile))) {
+        return Integer.parseInt(StringUtils.trim(reader.readLine()));
+      }
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private int readPidFileWithValidation() {
+    int pid = readPidFile(getPidFile());
+    assertThat(pid).isGreaterThan(0);
+    assertThat(isProcessAlive(pid)).isTrue();
+    return pid;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LauncherMemberMXBeanIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LauncherMemberMXBeanIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LauncherMemberMXBeanIntegrationTest.java
index 7b6cd7f..087f13b 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/LauncherMemberMXBeanIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LauncherMemberMXBeanIntegrationTest.java
@@ -14,136 +14,126 @@
  */
 package org.apache.geode.distributed;
 
-import org.apache.geode.cache.CacheFactory;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.management.MemberMXBean;
-import org.apache.geode.test.junit.categories.IntegrationTest;
+import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static javax.management.MBeanServerInvocationHandler.newProxyInstance;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Properties;
+import java.util.Set;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.Query;
+import javax.management.QueryExp;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import javax.management.*;
-import java.lang.management.ManagementFactory;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.Callable;
-
-import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.junit.Assert.*;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.internal.process.ControllableProcess;
+import org.apache.geode.internal.process.ProcessType;
+import org.apache.geode.management.MemberMXBean;
+import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
- * Tests querying of MemberMXBean which is used by MBeanProcessController to control GemFire
- * ControllableProcesses.
+ * Integration tests for querying of {@link MemberMXBean} as used in MBeanProcessController to
+ * manage a {@link ControllableProcess}.
+ *
+ * <p>
+ * This test is an experiment in using given/when/then custom methods for better BDD readability.
  * 
  * @since GemFire 8.0
  */
 @Category(IntegrationTest.class)
-public class LauncherMemberMXBeanIntegrationTest extends AbstractLauncherIntegrationTestCase {
-
-  @Before
-  public final void setUpLauncherMemberMXBeanIntegrationTest() throws Exception {}
+public class LauncherMemberMXBeanIntegrationTest extends LauncherIntegrationTestCase {
 
-  @After
-  public final void tearDownLauncherMemberMXBeanIntegrationTest() throws Exception {
-    InternalDistributedSystem ids = InternalDistributedSystem.getConnectedInstance();
-    if (ids != null) {
-      ids.disconnect();
-    }
-  }
+  private ObjectName pattern;
+  private QueryExp constraint;
+  private Set<ObjectName> mbeanNames;
 
-  @Test
-  public void testQueryForMemberMXBean() throws Exception {
-    final Properties props = new Properties();
+  @Before
+  public void setUp() throws Exception {
+    Properties props = new Properties();
     props.setProperty(MCAST_PORT, "0");
     props.setProperty(LOCATORS, "");
     props.setProperty("name", getUniqueName());
     new CacheFactory(props).create();
 
-    final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
-    final ObjectName pattern = ObjectName.getInstance("GemFire:type=Member,*");
+    pattern = ObjectName.getInstance("GemFire:type=Member,*");
+    waitForMemberMXBean(getPlatformMBeanServer(), pattern);
+  }
 
-    waitForMemberMXBean(mbeanServer, pattern);
+  @After
+  public void tearDown() throws Exception {
+    disconnectFromDS();
+  }
 
-    final Set<ObjectName> mbeanNames = mbeanServer.queryNames(pattern, null);
-    assertFalse(mbeanNames.isEmpty());
-    assertEquals("mbeanNames=" + mbeanNames, 1, mbeanNames.size());
+  @Test
+  public void queryWithNullFindsMemberMXBean() throws Exception {
+    givenConstraint(null);
 
-    final ObjectName objectName = mbeanNames.iterator().next();
-    final MemberMXBean mbean = MBeanServerInvocationHandler.newProxyInstance(mbeanServer,
-        objectName, MemberMXBean.class, false);
+    whenQuerying(getPlatformMBeanServer());
 
-    assertNotNull(mbean);
-    assertEquals(ProcessUtils.identifyPid(), mbean.getProcessId());
-    assertEquals(getUniqueName(), mbean.getName());
-    assertEquals(getUniqueName(), mbean.getMember());
+    thenMemberMXBeanShouldBeFound().andShouldMatchCurrentMember();
   }
 
   @Test
-  public void testQueryForMemberMXBeanWithProcessId() throws Exception {
-    final Properties props = new Properties();
-    props.setProperty(MCAST_PORT, "0");
-    props.setProperty(LOCATORS, "");
-    props.setProperty("name", getUniqueName());
-    new CacheFactory(props).create();
+  public void queryWithProcessIdFindsMemberMXBean() throws Exception {
+    givenConstraint(Query.eq(Query.attr("ProcessId"), Query.value(localPid)));
 
-    final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
-    final ObjectName pattern = ObjectName.getInstance("GemFire:type=Member,*");
-    final QueryExp constraint =
-        Query.eq(Query.attr("ProcessId"), Query.value(ProcessUtils.identifyPid()));
+    whenQuerying(getPlatformMBeanServer());
 
-    waitForMemberMXBean(mbeanServer, pattern);
+    thenMemberMXBeanShouldBeFound().andShouldMatchCurrentMember();
+  }
 
-    final Set<ObjectName> mbeanNames = mbeanServer.queryNames(pattern, constraint);
-    assertFalse(mbeanNames.isEmpty());
-    assertEquals(1, mbeanNames.size());
+  @Test
+  public void queryWithMemberNameFindsMemberMXBean() throws Exception {
+    givenConstraint(Query.eq(Query.attr("Name"), Query.value(getUniqueName())));
 
-    final ObjectName objectName = mbeanNames.iterator().next();
-    final MemberMXBean mbean = MBeanServerInvocationHandler.newProxyInstance(mbeanServer,
-        objectName, MemberMXBean.class, false);
+    whenQuerying(getPlatformMBeanServer());
 
-    assertNotNull(mbean);
-    assertEquals(ProcessUtils.identifyPid(), mbean.getProcessId());
-    assertEquals(getUniqueName(), mbean.getName());
-    assertEquals(getUniqueName(), mbean.getMember());
+    thenMemberMXBeanShouldBeFound().andShouldMatchCurrentMember();
   }
 
-  @Test
-  public void testQueryForMemberMXBeanWithMemberName() throws Exception {
-    final Properties props = new Properties();
-    props.setProperty(MCAST_PORT, "0");
-    props.setProperty(LOCATORS, "");
-    props.setProperty("name", getUniqueName());
-    new CacheFactory(props).create();
+  private void givenConstraint(final QueryExp constraint) {
+    this.constraint = constraint;
+  }
 
-    final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
-    final ObjectName pattern = ObjectName.getInstance("GemFire:type=Member,*");
-    final QueryExp constraint = Query.eq(Query.attr("Name"), Query.value(getUniqueName()));
+  private void whenQuerying(final MBeanServer mbeanServer) {
+    mbeanNames = mbeanServer.queryNames(pattern, constraint);
+  }
+
+  private LauncherMemberMXBeanIntegrationTest thenMemberMXBeanShouldBeFound() {
+    assertThat(mbeanNames).hasSize(1);
 
-    waitForMemberMXBean(mbeanServer, pattern);
+    return this;
+  }
 
-    final Set<ObjectName> mbeanNames = mbeanServer.queryNames(pattern, constraint);
-    assertFalse(mbeanNames.isEmpty());
-    assertEquals(1, mbeanNames.size());
+  private LauncherMemberMXBeanIntegrationTest andShouldMatchCurrentMember() {
+    ObjectName objectName = mbeanNames.iterator().next();
+    MemberMXBean mbean =
+        newProxyInstance(getPlatformMBeanServer(), objectName, MemberMXBean.class, false);
 
-    final ObjectName objectName = mbeanNames.iterator().next();
-    final MemberMXBean mbean = MBeanServerInvocationHandler.newProxyInstance(mbeanServer,
-        objectName, MemberMXBean.class, false);
+    assertThat(mbean.getMember()).isEqualTo(getUniqueName());
+    assertThat(mbean.getName()).isEqualTo(getUniqueName());
+    assertThat(mbean.getProcessId()).isEqualTo(localPid);
+
+    return this;
+  }
 
-    assertNotNull(mbean);
-    assertEquals(getUniqueName(), mbean.getMember());
+  @Override
+  protected ProcessType getProcessType() {
+    throw new UnsupportedOperationException(
+        "getProcessType is not used by " + getClass().getSimpleName());
   }
 
-  private void waitForMemberMXBean(final MBeanServer mbeanServer, final ObjectName pattern)
-      throws Exception {
-    assertEventuallyTrue("waiting for MemberMXBean to be registered", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        Set<ObjectName> mbeanNames = mbeanServer.queryNames(pattern, null);
-        return !mbeanNames.isEmpty();
-      }
-    }, WAIT_FOR_MBEAN_TIMEOUT, INTERVAL_MILLISECONDS);
+  private void waitForMemberMXBean(final MBeanServer mbeanServer, final ObjectName pattern) {
+    await().atMost(2, MINUTES)
+        .until(() -> assertThat(mbeanServer.queryNames(pattern, null)).isNotEmpty());
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorCommand.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorCommand.java
new file mode 100644
index 0000000..ef809af
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorCommand.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.geode.distributed.LocatorLauncher.Command;
+
+public class LocatorCommand {
+
+  private String javaPath;
+  private List<String> jvmArguments = new ArrayList<>();
+  private String classPath;
+  private Command command;
+  private String name;
+  private boolean force;
+  private int port;
+
+  public LocatorCommand() {
+    // do nothing
+  }
+
+  public LocatorCommand(final UsesLocatorCommand user) {
+    this.javaPath = user.getJavaPath();
+    this.jvmArguments = user.getJvmArguments();
+    this.classPath = user.getClassPath();
+    this.name = user.getName();
+    this.command = Command.START;
+  }
+
+  public LocatorCommand withJavaPath(final String javaPath) {
+    this.javaPath = javaPath;
+    return this;
+  }
+
+  public LocatorCommand withJvmArguments(final List<String> jvmArguments) {
+    this.jvmArguments = jvmArguments;
+    return this;
+  }
+
+  public LocatorCommand addJvmArgument(final String arg) {
+    this.jvmArguments.add(arg);
+    return this;
+  }
+
+  public LocatorCommand withClassPath(final String classPath) {
+    this.classPath = classPath;
+    return this;
+  }
+
+  public LocatorCommand withCommand(final Command command) {
+    this.command = command;
+    return this;
+  }
+
+  public LocatorCommand withName(final String name) {
+    this.name = name;
+    return this;
+  }
+
+  public LocatorCommand force() {
+    return force(true);
+  }
+
+  public LocatorCommand force(final boolean value) {
+    this.force = value;
+    return this;
+  }
+
+  public LocatorCommand withPort(final int port) {
+    this.port = port;
+    return this;
+  }
+
+  public List<String> create() {
+    List<String> cmd = new ArrayList<>();
+    cmd.add(javaPath);
+    cmd.addAll(jvmArguments);
+    cmd.add("-cp");
+    cmd.add(classPath);
+    cmd.add(LocatorLauncher.class.getName());
+    cmd.add(command.getName());
+    cmd.add(name);
+    if (force) {
+      cmd.add("--force");
+    }
+    cmd.add("--redirect-output");
+    if (port > 0) {
+      cmd.add("--port=" + port);
+    }
+    return cmd;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherBuilderTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherBuilderTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherBuilderTest.java
new file mode 100644
index 0000000..cc01e6c
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherBuilderTest.java
@@ -0,0 +1,507 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.apache.geode.internal.DistributionLocator.DEFAULT_LOCATOR_PORT;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import joptsimple.OptionException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.distributed.LocatorLauncher.Builder;
+import org.apache.geode.distributed.LocatorLauncher.Command;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link LocatorLauncher.Builder}. Extracted from {@link LocatorLauncherTest}.
+ */
+@Category(UnitTest.class)
+public class LocatorLauncherBuilderTest {
+
+  private InetAddress localHost;
+
+  @Rule
+  public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+  @Before
+  public void setUp() throws Exception {
+    localHost = InetAddress.getLocalHost();
+  }
+
+  @Test
+  public void defaultCommandIsUnspecified() throws Exception {
+    assertThat(Builder.DEFAULT_COMMAND).isEqualTo(Command.UNSPECIFIED);
+  }
+
+  @Test
+  public void getCommandReturnsUnspecifiedByDefault() throws Exception {
+    assertThat(new Builder().getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void getForceReturnsFalseByDefault() {
+    assertThat(new Builder().getForce()).isFalse();
+  }
+
+  @Test
+  public void getBindAddressReturnsNullByDefault() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.getBindAddress()).isNull();
+  }
+
+  @Test
+  public void getHostnameForClientsReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getHostnameForClients()).isNull();
+  }
+
+  @Test
+  public void getMemberNameReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getMemberName()).isNull();
+  }
+
+  @Test
+  public void getPidReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getPid()).isNull();
+  }
+
+  @Test
+  public void getPortReturnsDefaultLocatorPortByDefault() throws Exception {
+    assertThat(new Builder().getPort()).isEqualTo(Integer.valueOf(DEFAULT_LOCATOR_PORT));
+  }
+
+  @Test
+  public void setCommandReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setCommand(Command.STATUS)).isSameAs(builder);
+  }
+
+  @Test
+  public void setForceReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setForce(true)).isSameAs(builder);
+  }
+
+  @Test
+  public void setHostNameForClientsReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setHostnameForClients("Pegasus")).isSameAs(builder);
+  }
+
+  @Test
+  public void setMemberNameReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setMemberName("serverOne")).isSameAs(builder);
+  }
+
+  @Test
+  public void setBindAddressReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setBindAddress(null)).isSameAs(builder);
+  }
+
+  @Test
+  public void setPortReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setPort(null)).isSameAs(builder);
+  }
+
+  @Test
+  public void setCommandWithNullResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    new Builder().setCommand(null);
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void setCommandToStatusResultsInStatus() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setCommand(Command.STATUS);
+
+    assertThat(builder.getCommand()).isEqualTo(Command.STATUS);
+  }
+
+  @Test
+  public void setBindAddressToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setBindAddress(null);
+
+    assertThat(builder.getBindAddress()).isNull();
+  }
+
+  @Test
+  public void setBindAddressToEmptyStringResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setBindAddress("");
+
+    assertThat(builder.getBindAddress()).isNull();
+  }
+
+  @Test
+  public void setBindAddressToBlankStringResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setBindAddress("  ");
+
+    assertThat(builder.getBindAddress()).isNull();
+  }
+
+  @Test
+  public void setBindAddressToCanonicalLocalHostUsesValue() throws Exception {
+    Builder builder = new Builder().setBindAddress(InetAddress.getLocalHost().getHostName());
+
+    assertThat(builder.getBindAddress()).isEqualTo(localHost);
+  }
+
+  @Test
+  public void setBindAddressToLocalHostNameUsesValue() throws Exception {
+    String host = InetAddress.getLocalHost().getHostName();
+
+    Builder builder = new Builder().setBindAddress(host);
+
+    assertThat(builder.getBindAddress()).isEqualTo(localHost);
+  }
+
+  @Test
+  public void setBindAddressToUnknownHostThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setBindAddress("badhostname.badcompany.bad"))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasCauseInstanceOf(UnknownHostException.class);
+  }
+
+  @Test
+  public void setBindAddressToNonLocalHostThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setBindAddress("yahoo.com"))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setForceToTrueUsesValue() throws Exception {
+    ServerLauncher.Builder builder = new ServerLauncher.Builder();
+
+    builder.setForce(true);
+
+    assertThat(builder.getForce()).isTrue();
+  }
+
+  @Test
+  public void setHostnameForClientsToStringUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setHostnameForClients("Pegasus");
+
+    assertThat(builder.getHostnameForClients()).isEqualTo("Pegasus");
+  }
+
+  @Test
+  public void setHostnameForClientsToBlankStringThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setHostnameForClients(" "))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setHostnameForClientsToEmptyStringThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setHostnameForClients(""))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+
+  public void setHostnameForClientsToNullThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setHostnameForClients(null))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMemberNameToStringUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMemberName("locatorOne");
+
+    assertThat(builder.getMemberName()).isEqualTo("locatorOne");
+  }
+
+  @Test
+  public void setMemberNameWithBlankStringThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setMemberName("  "))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMemberNameWithEmptyStringThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setMemberName(""))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMemberNameWithNullStringThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setMemberName(null))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setPidToZeroOrGreaterUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setPid(0);
+    assertThat(builder.getPid().intValue()).isEqualTo(0);
+
+    builder.setPid(1);
+    assertThat(builder.getPid().intValue()).isEqualTo(1);
+
+    builder.setPid(1024);
+    assertThat(builder.getPid().intValue()).isEqualTo(1024);
+
+    builder.setPid(12345);
+    assertThat(builder.getPid().intValue()).isEqualTo(12345);
+  }
+
+  @Test
+  public void setPidToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setPid(null);
+
+    assertThat(builder.getPid()).isNull();
+  }
+
+  @Test
+  public void setPidToNegativeValueThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setPid(-1)).isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setPortToNullUsesDefaultLocatorPort() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setPort(null).getPort()).isEqualTo(Integer.valueOf(DEFAULT_LOCATOR_PORT));
+  }
+
+  @Test
+  public void setPortToZeroOrGreaterUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setPort(0);
+    assertThat(builder.getPort().intValue()).isEqualTo(0);
+
+    builder.setPort(1);
+    assertThat(builder.getPort().intValue()).isEqualTo(1);
+
+    builder.setPort(80);
+    assertThat(builder.getPort().intValue()).isEqualTo(80);
+
+    builder.setPort(1024);
+    assertThat(builder.getPort().intValue()).isEqualTo(1024);
+
+    builder.setPort(65535);
+    assertThat(builder.getPort().intValue()).isEqualTo(65535);
+  }
+
+  @Test
+  public void setPortAboveMaxValueThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setPort(65536))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setPortToNegativeValueThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setPort(-1))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void parseArgumentsWithForceSetsForceToTrue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseArguments("start", "--force");
+
+    assertThat(builder.getForce()).isTrue();
+  }
+
+  @Test
+  public void parseArgumentsWithNonNumericPortThrowsIllegalArgumentException() {
+    assertThatThrownBy(
+        () -> new Builder().parseArguments("start", "locator1", "--port", "oneTwoThree"))
+            .isInstanceOf(IllegalArgumentException.class).hasCauseInstanceOf(OptionException.class);
+  }
+
+  @Test
+  public void parseCommandWithNullStringArrayResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand((String[]) null);
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void parseCommandWithEmptyStringArrayResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand(); // empty String array
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void parseCommandWithStartResultsInStartCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand(Command.START.getName());
+
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+  }
+
+  @Test
+  public void parseCommandWithStatusResultsInStatusCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("Status");
+
+    assertThat(builder.getCommand()).isEqualTo(Command.STATUS);
+  }
+
+  @Test
+  public void parseCommandWithMixedCaseResultsInCorrectCase() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("sToP");
+
+    assertThat(builder.getCommand()).isEqualTo(Command.STOP);
+  }
+
+  @Test
+  public void parseCommandWithTwoCommandsWithSwitchesUsesFirstCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("--opt", "START", "-o", Command.STATUS.getName());
+
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+  }
+
+  @Test
+  public void parseCommandWithTwoCommandsWithoutSwitchesUsesFirstCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("START", Command.STATUS.getName());
+
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+  }
+
+  @Test
+  public void parseCommandWithBadInputResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("badCommandName", "--start", "stat");
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void parseMemberNameWithNullStringArrayResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName((String[]) null);
+
+    assertThat(builder.getMemberName()).isNull();
+  }
+
+  @Test
+  public void parseMemberNameWithEmptyStringArrayResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName(); // empty String array
+
+    assertThat(builder.getMemberName()).isNull();
+  }
+
+  @Test
+  public void parseMemberNameWithCommandAndOptionsResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName(Command.START.getName(), "--opt", "-o");
+
+    assertThat(builder.getMemberName()).isNull();
+  }
+
+  @Test
+  public void parseMemberNameWithStringUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName("memberOne");
+
+    assertThat(builder.getMemberName()).isEqualTo("memberOne");
+  }
+
+
+  @Test
+  public void buildCreatesLocatorLauncherWithBuilderValues() throws Exception {
+    Builder builder = new Builder();
+
+    LocatorLauncher launcher = builder.setCommand(Command.START).setDebug(true)
+        .setHostnameForClients("beanstock.vmware.com").setMemberName("Beanstock").setPort(8192)
+        .build();
+
+    assertThat(launcher.getCommand()).isEqualTo(builder.getCommand());
+    assertThat(launcher.isDebugging()).isTrue();
+    assertThat(launcher.getHostnameForClients()).isEqualTo(builder.getHostnameForClients());
+    assertThat(launcher.getMemberName()).isEqualTo(builder.getMemberName());
+    assertThat(launcher.getPort()).isEqualTo(builder.getPort());
+    assertThat(launcher.getWorkingDirectory()).isEqualTo(builder.getWorkingDirectory());
+
+    assertThat(launcher.isHelping()).isFalse();
+    assertThat(launcher.isRunning()).isFalse();
+  }
+
+  @Test
+  public void buildUsesMemberNameSetInApiProperties() {
+    LocatorLauncher launcher =
+        new Builder().setCommand(LocatorLauncher.Command.START).set(NAME, "locatorABC").build();
+
+    assertThat(launcher.getMemberName()).isNull();
+    assertThat(launcher.getProperties().getProperty(NAME)).isEqualTo("locatorABC");
+  }
+
+  @Test
+  public void buildUsesMemberNameSetInSystemPropertiesOnStart() {
+    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + NAME, "locatorXYZ");
+
+    LocatorLauncher launcher = new Builder().setCommand(LocatorLauncher.Command.START).build();
+
+    assertThat(launcher.getCommand()).isEqualTo(LocatorLauncher.Command.START);
+    assertThat(launcher.getMemberName()).isNull();
+  }
+}


[22/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
GEODE-3413: overhaul launcher and process classes and tests

This is primarily an overall of all ServerLauncher and LocatorLauncher
tests and org.apache.geode.internal.process tests. The main classes in
org.apachage.geode.internal.process package are also cleaned up.

In addition, several bugs involving these classes and tests are fixed.

Here is the complete list of tickets that are resolved in this overhaul:

* GEODE-1229: LocatorLauncherRemoteJUnitTest.testStartOverwritesStalePidFile
* GEODE-2791: LocatorLauncherAssemblyIntegrationTest.testLocatorStopsWhenJmxPortIsNonZero fails intermittently with AssertionError
* GEODE-1308: CI failure: LocatorLauncherTest.testSetBindAddressToNonLocalHost
* GEODE-1309: CI failure: ServerLauncherTest.testSetServerBindAddressToNonLocalHost
* GEODE-3193: locator pid file is removed even if there was a problem while shutting down
* GEODE-3413: Overhaul launcher tests and process tests
* GEODE-3414: Cleanup org.apache.geode.internal.process package

Note I moved all useful tests from LocatorLauncherAssemblyIntegrationTest
into the other launcher tests in geode-core.


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/894f3ee7
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/894f3ee7
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/894f3ee7

Branch: refs/heads/feature/GEODE-3304
Commit: 894f3ee710e500c83f06be660b852d389cbb94cb
Parents: beebb65
Author: Kirk Lund <kl...@apache.org>
Authored: Mon Jul 10 12:30:09 2017 -0700
Committer: Kirk Lund <kl...@apache.org>
Committed: Fri Aug 11 10:00:16 2017 -0700

----------------------------------------------------------------------
 .../LocatorLauncherAssemblyIntegrationTest.java |  150 --
 .../geode/distributed/AbstractLauncher.java     |  139 +-
 .../geode/distributed/LocatorLauncher.java      |  377 +++--
 .../geode/distributed/ServerLauncher.java       |  420 ++---
 .../distributed/internal/InternalLocator.java   |    5 +-
 .../cache/ClusterConfigurationLoader.java       |   35 +-
 .../geode/internal/cache/GemFireCacheImpl.java  |    9 +-
 ...usterConfigurationNotAvailableException.java |   29 +
 .../geode/internal/io/TeePrintStream.java       |    2 +-
 .../internal/process/AttachProcessUtils.java    |    9 +-
 .../process/BlockingProcessStreamReader.java    |   33 +-
 ...usterConfigurationNotAvailableException.java |    8 +-
 .../process/ConnectionFailedException.java      |   14 +-
 .../internal/process/ControlFileWatchdog.java   |  124 +-
 .../process/ControlNotificationHandler.java     |    5 +-
 .../internal/process/ControllableProcess.java   |  196 ++-
 .../process/FileAlreadyExistsException.java     |   14 +-
 .../process/FileControllerParameters.java       |    5 +-
 .../internal/process/FileProcessController.java |  111 +-
 .../process/LocalProcessController.java         |  478 ------
 .../internal/process/LocalProcessLauncher.java  |  101 +-
 .../process/MBeanControllerParameters.java      |   13 +-
 .../process/MBeanInvocationFailedException.java |   14 +-
 .../process/MBeanProcessController.java         |  128 +-
 .../internal/process/NativeProcessUtils.java    |   14 +-
 .../process/NonBlockingProcessStreamReader.java |   88 +-
 .../apache/geode/internal/process/PidFile.java  |  113 +-
 .../process/PidUnavailableException.java        |   14 +-
 .../internal/process/ProcessController.java     |   17 +-
 .../process/ProcessControllerFactory.java       |   72 +-
 .../process/ProcessControllerParameters.java    |    6 +-
 .../process/ProcessLauncherContext.java         |   68 +-
 .../internal/process/ProcessStreamReader.java   |  161 +-
 .../ProcessTerminatedAbnormallyException.java   |   97 --
 .../geode/internal/process/ProcessType.java     |   24 +-
 .../geode/internal/process/ProcessUtils.java    |   66 +-
 .../geode/internal/process/StartupStatus.java   |   20 +-
 .../internal/process/StartupStatusListener.java |    2 +-
 .../UnableToControlProcessException.java        |   14 +-
 .../AbstractSignalNotificationHandler.java      |   81 +-
 .../geode/internal/process/signal/Signal.java   |   20 +-
 .../internal/process/signal/SignalEvent.java    |   11 +-
 .../internal/process/signal/SignalListener.java |    8 +-
 .../internal/process/signal/SignalType.java     |    7 +-
 .../cli/commands/StartServerCommand.java        |    3 -
 .../AbstractLauncherIntegrationTest.java        |   49 +-
 .../AbstractLauncherIntegrationTestCase.java    |  268 ---
 .../AbstractLauncherServiceStateTest.java       |  224 +++
 .../AbstractLauncherServiceStatusTest.java      |  224 ---
 .../geode/distributed/AbstractLauncherTest.java |  462 +++--
 ...tractLocatorLauncherIntegrationTestCase.java |  135 --
 ...ocatorLauncherRemoteIntegrationTestCase.java |   65 -
 ...stractServerLauncherIntegrationTestCase.java |   98 --
 ...ServerLauncherRemoteIntegrationTestCase.java |   95 --
 .../LauncherIntegrationTestCase.java            |  314 ++++
 .../LauncherMemberMXBeanIntegrationTest.java    |  174 +-
 .../geode/distributed/LocatorCommand.java       |  107 ++
 .../distributed/LocatorLauncherBuilderTest.java |  507 ++++++
 .../LocatorLauncherIntegrationTest.java         |  278 +--
 .../LocatorLauncherIntegrationTestCase.java     |  163 ++
 ...orLauncherJmxManagerLocalRegressionTest.java |  111 ++
 ...rLauncherJmxManagerRemoteRegressionTest.java |   72 +
 ...LocatorLauncherLocalFileIntegrationTest.java |   35 +-
 .../LocatorLauncherLocalIntegrationTest.java    |  886 +++-------
 ...ocatorLauncherRemoteFileIntegrationTest.java |  211 +--
 .../LocatorLauncherRemoteIntegrationTest.java   | 1092 ++----------
 ...ocatorLauncherRemoteIntegrationTestCase.java |  234 +++
 ...rRemoteWithCustomLoggingIntegrationTest.java |  104 +-
 .../geode/distributed/LocatorLauncherTest.java  |  344 +---
 .../geode/distributed/LocatorStateTest.java     |  185 +-
 .../MockServerLauncherCacheProvider.java        |   38 -
 .../apache/geode/distributed/ServerCommand.java |  120 ++
 .../distributed/ServerLauncherBuilderTest.java  |  845 ++++++++++
 .../ServerLauncherIntegrationTest.java          |  349 ++--
 .../ServerLauncherIntegrationTestCase.java      |  204 +++
 .../ServerLauncherLocalFileIntegrationTest.java |   24 +-
 .../ServerLauncherLocalIntegrationTest.java     | 1124 +++----------
 .../ServerLauncherLocalIntegrationTestCase.java |   26 +
 ...ServerLauncherRemoteFileIntegrationTest.java |  207 +--
 .../ServerLauncherRemoteIntegrationTest.java    | 1579 +++---------------
 ...ServerLauncherRemoteIntegrationTestCase.java |  236 +++
 ...rRemoteWithCustomLoggingIntegrationTest.java |  107 +-
 .../geode/distributed/ServerLauncherTest.java   |  968 ++---------
 ...erLauncherWaitOnServerMultiThreadedTest.java |  111 ++
 ...rverLauncherWithProviderIntegrationTest.java |   81 -
 ...erverLauncherWithProviderRegressionTest.java |   68 +
 .../TestServerLauncherCacheProvider.java        |   42 +
 .../geode/distributed/UsesLocatorCommand.java   |   28 +
 .../geode/distributed/UsesServerCommand.java    |   30 +
 .../support/DistributedSystemAdapter.java       |  272 ---
 ...tractProcessStreamReaderIntegrationTest.java |  309 ++++
 .../process/AttachProcessUtilsTest.java         |   85 +
 .../BaseProcessStreamReaderIntegrationTest.java |   51 +
 ...ckingProcessStreamReaderIntegrationTest.java |  133 ++
 .../BlockingProcessStreamReaderJUnitTest.java   |  443 -----
 .../BlockingProcessStreamReaderWindowsTest.java |   93 ++
 .../ControlFileWatchdogIntegrationTest.java     |  241 +++
 .../ControllableProcessIntegrationTest.java     |  196 +++
 ...leProcessControllerIntegrationJUnitTest.java |  151 --
 .../FileProcessControllerIntegrationTest.java   |  249 +++
 .../process/FileProcessControllerTest.java      |   90 +
 .../LocalProcessControllerJUnitTest.java        |  121 --
 .../process/LocalProcessLauncherDUnitTest.java  |  154 --
 .../LocalProcessLauncherDistributedTest.java    |   92 +
 .../LocalProcessLauncherIntegrationTest.java    |  160 ++
 .../process/LocalProcessLauncherJUnitTest.java  |  177 --
 .../NativeProcessUtilsIntegrationTest.java      |  119 ++
 .../process/NativeProcessUtilsTest.java         |   76 +
 ...ckingProcessStreamReaderIntegrationTest.java |  130 ++
 ...NonBlockingProcessStreamReaderJUnitTest.java |  365 ----
 .../process/PidFileIntegrationTest.java         |  187 +++
 .../internal/process/PidFileJUnitTest.java      |  275 ---
 ...ProcessControllerFactoryIntegrationTest.java |  135 ++
 .../ProcessControllerFactoryJUnitTest.java      |  176 --
 .../process/ProcessControllerFactoryTest.java   |  116 ++
 .../process/ProcessLauncherContextTest.java     |  208 +++
 .../process/ProcessStreamReaderTestCase.java    |  254 ---
 .../internal/process/StartupStatusTest.java     |  176 ++
 .../internal/process/io/EmptyFileWriter.java    |   40 +
 .../internal/process/io/IntegerFileReader.java  |   38 +
 .../internal/process/io/IntegerFileWriter.java  |   33 +
 .../internal/process/io/StringFileWriter.java   |   43 +
 .../internal/process/lang/AvailablePid.java     |  106 ++
 .../internal/process/lang/AvailablePidTest.java |  107 ++
 .../geode/internal/process/mbean/Process.java   |   57 -
 .../internal/process/mbean/ProcessMBean.java    |   27 -
 ...tractSignalNotificationHandlerJUnitTest.java |  467 ------
 .../AbstractSignalNotificationHandlerTest.java  |  406 +++++
 ...eode.distributed.ServerLauncherCacheProvider |    2 +-
 .../codeAnalysis/sanctionedSerializables.txt    |    9 +-
 130 files changed, 10256 insertions(+), 12262 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-assembly/src/test/java/org/apache/geode/distributed/LocatorLauncherAssemblyIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/org/apache/geode/distributed/LocatorLauncherAssemblyIntegrationTest.java b/geode-assembly/src/test/java/org/apache/geode/distributed/LocatorLauncherAssemblyIntegrationTest.java
deleted file mode 100644
index 4e8d389..0000000
--- a/geode-assembly/src/test/java/org/apache/geode/distributed/LocatorLauncherAssemblyIntegrationTest.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import org.apache.geode.cache.Cache;
-import org.apache.geode.cache.CacheFactory;
-import org.apache.geode.distributed.AbstractLauncher.Status;
-import org.apache.geode.distributed.LocatorLauncher.Builder;
-import org.apache.geode.internal.AvailablePortHelper;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.management.ManagementService;
-import org.apache.geode.management.ManagerMXBean;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.io.File;
-
-import static org.junit.Assert.*;
-
-import static org.apache.geode.distributed.ConfigurationProperties.*;
-
-/**
- * These tests are part of assembly as they require the REST war file to be present.
- */
-@Category(IntegrationTest.class)
-@RunWith(Parameterized.class)
-@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
-public class LocatorLauncherAssemblyIntegrationTest
-    extends AbstractLocatorLauncherIntegrationTestCase {
-
-  @Before
-  public final void setUpLocatorLauncherLocalTest() throws Exception {
-    disconnectFromDS();
-    System.setProperty(ProcessType.TEST_PREFIX_PROPERTY, getUniqueName() + "-");
-  }
-
-  @After
-  public final void tearDownLocatorLauncherLocalTest() throws Exception {
-    disconnectFromDS();
-  }
-
-  /*
-   * This test addresses GEODE-528
-   */
-  @Test
-  public void testLocatorStopsWhenJmxPortIsZero() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(false).setWorkingDirectory(rootFolder).set(LOG_LEVEL, "config")
-        .set(ENABLE_CLUSTER_CONFIGURATION, "false").set(JMX_MANAGER, "true")
-        .set(JMX_MANAGER_START, "true").set(JMX_MANAGER_PORT, "0");
-
-    performTest(builder);
-  }
-
-  /*
-   * This test addresses GEODE-528
-   */
-  @Test
-  public void testLocatorStopsWhenJmxPortIsNonZero() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-    final int jmxPort = AvailablePortHelper.getRandomAvailableTCPPorts(1)[0];
-
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(false).setWorkingDirectory(rootFolder).set(LOG_LEVEL, "config")
-        .set(ENABLE_CLUSTER_CONFIGURATION, "false").set(JMX_MANAGER, "true")
-        .set(JMX_MANAGER_START, "true").set(JMX_MANAGER_PORT, Integer.toString(jmxPort));
-
-    performTest(builder);
-  }
-
-  private void performTest(Builder builder) {
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    LocatorLauncher dirLauncher = null;
-    int initialThreadCount = Thread.activeCount();
-
-    try {
-      this.launcher.start();
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue("Pid file " + this.pidFile.getCanonicalPath().toString() + " should exist",
-          this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      dirLauncher = new Builder().setWorkingDirectory(builder.getWorkingDirectory()).build();
-      assertNotNull(dirLauncher);
-      assertFalse(dirLauncher.isRunning());
-
-      // Stop the manager
-      Cache cache = CacheFactory.getAnyInstance();
-      ManagerMXBean managerBean = ManagementService.getManagementService(cache).getManagerMXBean();
-      managerBean.stop();
-
-      // stop the locator
-      final LocatorLauncher.LocatorState locatorState = dirLauncher.stop();
-      assertNotNull(locatorState);
-      assertEquals(Status.STOPPED, locatorState.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // verify the PID file was deleted
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    int finalThreadCount = Integer.MAX_VALUE;
-
-    // Spin for up to 5 seconds waiting for threads to finish
-    for (int i = 0; i < 50 && finalThreadCount > initialThreadCount; i++) {
-      try {
-        Thread.sleep(100);
-      } catch (InterruptedException ex) {
-        // ignored
-      }
-      finalThreadCount = Thread.activeCount();
-    }
-
-    assertEquals(initialThreadCount, finalThreadCount);
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/AbstractLauncher.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/AbstractLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/AbstractLauncher.java
index 28a156a..952afa8 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/AbstractLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/AbstractLauncher.java
@@ -12,33 +12,24 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.distributed;
 
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang.StringUtils.join;
+import static org.apache.commons.lang.StringUtils.lowerCase;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
-
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.distributed.internal.unsafe.RegisterSignalHandlerSupport;
-import org.apache.geode.internal.AvailablePort;
-import org.apache.geode.internal.GemFireVersion;
-import org.apache.geode.internal.OSProcess;
-import org.apache.geode.internal.i18n.LocalizedStrings;
-import org.apache.geode.internal.lang.ClassUtils;
-import org.apache.geode.internal.lang.ObjectUtils;
-import org.apache.geode.internal.lang.StringUtils;
-import org.apache.geode.internal.lang.SystemUtils;
-import org.apache.geode.internal.process.PidUnavailableException;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.internal.util.ArgumentRedactor;
-import org.apache.geode.internal.util.SunAPINotFoundException;
-import org.apache.geode.management.internal.cli.json.GfJsonObject;
+import static org.apache.geode.internal.lang.ClassUtils.forName;
+import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
+import static org.apache.geode.internal.lang.StringUtils.defaultString;
+import static org.apache.geode.internal.lang.SystemUtils.CURRENT_DIRECTORY;
 
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.net.BindException;
 import java.net.InetAddress;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
@@ -50,10 +41,21 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.logging.FileHandler;
-import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.InternalDistributedSystem;
+import org.apache.geode.distributed.internal.unsafe.RegisterSignalHandlerSupport;
+import org.apache.geode.internal.AvailablePort;
+import org.apache.geode.internal.GemFireVersion;
+import org.apache.geode.internal.OSProcess;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.process.PidUnavailableException;
+import org.apache.geode.internal.process.ProcessUtils;
+import org.apache.geode.internal.util.ArgumentRedactor;
+import org.apache.geode.internal.util.SunAPINotFoundException;
+import org.apache.geode.management.internal.cli.json.GfJsonObject;
+
 /**
  * The AbstractLauncher class is a base class for implementing various launchers to construct and
  * run different GemFire processes, like Cache Servers, Locators, Managers, HTTP servers and so on.
@@ -67,9 +69,13 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
 
   protected static final Boolean DEFAULT_FORCE = Boolean.FALSE;
 
+  /**
+   * @deprecated This timeout is no longer needed.
+   */
+  @Deprecated
   protected static final long READ_PID_FILE_TIMEOUT_MILLIS = 2 * 1000;
 
-  public static final String DEFAULT_WORKING_DIRECTORY = SystemUtils.CURRENT_DIRECTORY;
+  public static final String DEFAULT_WORKING_DIRECTORY = CURRENT_DIRECTORY;
 
   public static final String SIGNAL_HANDLER_REGISTRATION_SYSTEM_PROPERTY =
       DistributionConfig.GEMFIRE_PREFIX + "launcher.registerSignalHandlers";
@@ -88,12 +94,12 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
   public AbstractLauncher() {
     try {
       if (Boolean.getBoolean(SIGNAL_HANDLER_REGISTRATION_SYSTEM_PROPERTY)) {
-        ClassUtils.forName(SUN_SIGNAL_API_CLASS_NAME, new SunAPINotFoundException(
+        forName(SUN_SIGNAL_API_CLASS_NAME, new SunAPINotFoundException(
             "WARNING!!! Not running a Sun JVM.  Could not find the sun.misc.Signal class; Signal handling disabled."));
         RegisterSignalHandlerSupport.registerSignalHandlers();
       }
-    } catch (SunAPINotFoundException e) {
-      info(e.getMessage());
+    } catch (SunAPINotFoundException handled) {
+      info(handled.getMessage());
     }
   }
 
@@ -102,7 +108,6 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
    *
    * @param port an integer indicating the network port to listen for client network requests.
    * @throws BindException if the network port is not available.
-   * @see #assertPortAvailable
    */
   protected static void assertPortAvailable(final int port) throws BindException {
     assertPortAvailable(null, port);
@@ -124,7 +129,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
     if (!AvailablePort.isPortAvailable(port, AvailablePort.SOCKET, bindAddress)) {
       throw new BindException(
           String.format("Network is unreachable; port (%1$d) is not available on %2$s.", port,
-              (bindAddress != null ? bindAddress.getCanonicalHostName() : "localhost")));
+              bindAddress != null ? bindAddress.getCanonicalHostName() : "localhost"));
     }
   }
 
@@ -141,7 +146,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
    * @see java.util.Properties
    */
   protected static boolean isSet(final Properties properties, final String propertyName) {
-    return StringUtils.isNotBlank(properties.getProperty(propertyName));
+    return isNotBlank(properties.getProperty(propertyName));
   }
 
   /**
@@ -152,34 +157,27 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
    * @see java.net.URL
    */
   protected static Properties loadGemFireProperties(final URL url) {
-    final Properties properties = new Properties();
+    if (url == null) {
+      return new Properties();
+    }
+    Properties properties = new Properties();
 
-    if (url != null) {
-      try {
-        properties.load(new FileReader(new File(url.toURI())));
-      } catch (Exception e) {
-        try {
-          // not in the file system, try the classpath
-          properties.load(
-              AbstractLauncher.class.getResourceAsStream(DistributedSystem.getPropertiesFile()));
-        } catch (Exception ignore) {
-          // not in the file system or the classpath; gemfire.properties does not exist
-        }
-      }
+    try {
+      properties.load(new FileReader(new File(url.toURI())));
+    } catch (IOException | URISyntaxException handled) {
+      // not in the file system, try the classpath
+      loadGemFirePropertiesFromClassPath(properties);
     }
 
     return properties;
   }
 
-  void initLogger() {
+  private static void loadGemFirePropertiesFromClassPath(Properties properties) {
     try {
-      this.logger.addHandler(new FileHandler(SystemUtils.CURRENT_DIRECTORY.concat("debug.log")));
-      this.logger.setLevel(Level.ALL);
-      this.logger.setUseParentHandlers(true);
-    } catch (IOException e) {
-      e.printStackTrace(System.err);
-      System.err.flush();
-      throw new RuntimeException(e);
+      properties
+          .load(AbstractLauncher.class.getResourceAsStream(DistributedSystem.getPropertiesFile()));
+    } catch (IOException | NullPointerException handled) {
+      // leave the properties empty
     }
   }
 
@@ -240,7 +238,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
       distributedSystemProperties.putAll(defaults);
     }
 
-    if (StringUtils.isNotBlank(getMemberName())) {
+    if (isNotBlank(getMemberName())) {
       distributedSystemProperties.setProperty(NAME, getMemberName());
     }
 
@@ -264,8 +262,8 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
   protected String getLogFileCanonicalPath() {
     try {
       return getLogFile().getCanonicalPath();
-    } catch (IOException e) {
-      return getLogFileName(); // TODO: or return null?
+    } catch (IOException handled) {
+      return getLogFileName();
     }
   }
 
@@ -288,10 +286,10 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
    * @see #getMemberId()
    */
   public String getMember() {
-    if (StringUtils.isNotBlank(getMemberName())) {
+    if (isNotBlank(getMemberName())) {
       return getMemberName();
     }
-    if (StringUtils.isNotBlank(getMemberId())) {
+    if (isNotBlank(getMemberId())) {
       return getMemberId();
     }
     return null;
@@ -307,7 +305,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
   public String getMemberId() {
     final InternalDistributedSystem distributedSystem =
         InternalDistributedSystem.getConnectedInstance();
-    return (distributedSystem != null ? distributedSystem.getMemberId() : null);
+    return distributedSystem != null ? distributedSystem.getMemberId() : null;
   }
 
   /**
@@ -319,7 +317,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
   public String getMemberName() {
     final InternalDistributedSystem distributedSystem =
         InternalDistributedSystem.getConnectedInstance();
-    return (distributedSystem != null ? distributedSystem.getConfig().getName() : null);
+    return distributedSystem != null ? distributedSystem.getConfig().getName() : null;
   }
 
   /**
@@ -430,7 +428,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
   int identifyPidOrNot() {
     try {
       return identifyPid();
-    } catch (PidUnavailableException e) {
+    } catch (PidUnavailableException handled) {
       return -1;
     }
   }
@@ -488,21 +486,19 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
 
     private final Timestamp timestamp;
 
-    // TODO refactor the logic in this method into a DateTimeFormatUtils class
     protected static String format(final Date timestamp) {
-      return (timestamp == null ? ""
-          : new SimpleDateFormat(DATE_TIME_FORMAT_PATTERN).format(timestamp));
+      return timestamp == null ? ""
+          : new SimpleDateFormat(DATE_TIME_FORMAT_PATTERN).format(timestamp);
     }
 
     protected static Integer identifyPid() {
       try {
         return ProcessUtils.identifyPid();
-      } catch (PidUnavailableException ignore) {
+      } catch (PidUnavailableException handled) {
         return null;
       }
     }
 
-    // TODO refactor the logic in this method into a DateTimeFormatUtils class
     protected static String toDaysHoursMinutesSeconds(final Long milliseconds) {
       final StringBuilder buffer = new StringBuilder();
 
@@ -555,7 +551,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
       this.pid = pid;
       this.uptime = uptime;
       this.workingDirectory = workingDirectory;
-      this.jvmArguments = ObjectUtils.defaultIfNull(Collections.unmodifiableList(jvmArguments),
+      this.jvmArguments = defaultIfNull(Collections.unmodifiableList(jvmArguments),
           Collections.<String>emptyList());
       this.classpath = classpath;
       this.gemfireVersion = gemfireVersion;
@@ -592,12 +588,11 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
     }
 
     public static boolean isStartingNotRespondingOrNull(final ServiceState serviceState) {
-      return (serviceState == null || serviceState.isStartingOrNotResponding());
+      return serviceState == null || serviceState.isStartingOrNotResponding();
     }
 
     public boolean isStartingOrNotResponding() {
-      return (Status.NOT_RESPONDING.equals(this.getStatus())
-          || Status.STARTING.equals(this.getStatus()));
+      return Status.NOT_RESPONDING == getStatus() || Status.STARTING == getStatus();
     }
 
     public boolean isVmWithProcessIdRunning() {
@@ -729,7 +724,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
      * @return a String value indicating the GemFire service's working (running) directory.
      */
     public String getWorkingDirectory() {
-      return ObjectUtils.defaultIfNull(workingDirectory, DEFAULT_WORKING_DIRECTORY);
+      return defaultIfNull(workingDirectory, DEFAULT_WORKING_DIRECTORY);
     }
 
     /**
@@ -795,17 +790,17 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
 
     // the value of a Number as a String, or "" if null
     protected String toString(final Number value) {
-      return StringUtils.defaultString(value);
+      return defaultString(value);
     }
 
     // a String concatenation of all values separated by " "
     protected String toString(final Object... values) {
-      return values == null ? "" : StringUtils.join(values, " ");
+      return values == null ? "" : join(values, " ");
     }
 
     // the value of the String, or "" if value is null
     protected String toString(final String value) {
-      return ObjectUtils.defaultIfNull(value, "");
+      return defaultIfNull(value, "");
     }
   }
 
@@ -813,7 +808,7 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
    * The Status enumerated type represents the various lifecycle states of a GemFire service (such
    * as a Cache Server, a Locator or a Manager).
    */
-  public static enum Status {
+  public enum Status {
     NOT_RESPONDING(LocalizedStrings.Launcher_Status_NOT_RESPONDING.toLocalizedString()),
     ONLINE(LocalizedStrings.Launcher_Status_ONLINE.toLocalizedString()),
     STARTING(LocalizedStrings.Launcher_Status_STARTING.toLocalizedString()),
@@ -822,8 +817,8 @@ public abstract class AbstractLauncher<T extends Comparable<T>> implements Runna
     private final String description;
 
     Status(final String description) {
-      assert StringUtils.isNotBlank(description) : "The Status description must be specified!";
-      this.description = StringUtils.lowerCase(description);
+      assert isNotBlank(description) : "The Status description must be specified!";
+      this.description = lowerCase(description);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
index c5a2de8..83c1ab5 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/LocatorLauncher.java
@@ -12,11 +12,44 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.distributed;
 
+import static org.apache.commons.lang.StringUtils.defaultIfBlank;
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang.StringUtils.lowerCase;
 import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
+import static org.apache.geode.internal.lang.StringUtils.wrap;
+import static org.apache.geode.internal.lang.SystemUtils.CURRENT_DIRECTORY;
+import static org.apache.geode.internal.util.IOUtils.tryGetCanonicalPathElseGetAbsolutePath;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.logging.Level;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import joptsimple.OptionException;
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
 
 import org.apache.geode.cache.client.internal.locator.LocatorStatusRequest;
 import org.apache.geode.cache.client.internal.locator.LocatorStatusResponse;
@@ -28,8 +61,6 @@ import org.apache.geode.internal.DistributionLocator;
 import org.apache.geode.internal.GemFireVersion;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.lang.ObjectUtils;
-import org.apache.geode.internal.lang.StringUtils;
-import org.apache.geode.internal.lang.SystemUtils;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.process.ConnectionFailedException;
 import org.apache.geode.internal.process.ControlNotificationHandler;
@@ -45,37 +76,11 @@ import org.apache.geode.internal.process.ProcessType;
 import org.apache.geode.internal.process.ProcessUtils;
 import org.apache.geode.internal.process.StartupStatusListener;
 import org.apache.geode.internal.process.UnableToControlProcessException;
-import org.apache.geode.internal.util.IOUtils;
 import org.apache.geode.lang.AttachAPINotFoundException;
 import org.apache.geode.management.internal.cli.json.GfJsonArray;
 import org.apache.geode.management.internal.cli.json.GfJsonException;
 import org.apache.geode.management.internal.cli.json.GfJsonObject;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.net.ConnectException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.logging.Level;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-import joptsimple.OptionException;
-import joptsimple.OptionParser;
-import joptsimple.OptionSet;
-
 /**
  * The LocatorLauncher class is a launcher for a GemFire Locator.
  * 
@@ -104,6 +109,8 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     helpMap.put("bind-address",
         LocalizedStrings.LocatorLauncher_LOCATOR_BIND_ADDRESS_HELP.toLocalizedString());
     helpMap.put("debug", LocalizedStrings.LocatorLauncher_LOCATOR_DEBUG_HELP.toLocalizedString());
+    helpMap.put("delete-pid-file-on-stop",
+        "Specifies that this Locator's PID file should be deleted on stop.  The default is to not delete this Locator's PID file until JVM exit if --delete-pid-file-on-stop is not specified.");
     helpMap.put("dir", LocalizedStrings.LocatorLauncher_LOCATOR_DIR_HELP.toLocalizedString());
     helpMap.put("force", LocalizedStrings.LocatorLauncher_LOCATOR_FORCE_HELP.toLocalizedString());
     helpMap.put("help",
@@ -143,6 +150,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
 
   private final AtomicBoolean starting = new AtomicBoolean(false);
 
+  private final boolean deletePidFileOnStop;
   private final boolean force;
   private final boolean help;
   private final boolean redirectOutput;
@@ -181,8 +189,8 @@ public class LocatorLauncher extends AbstractLauncher<String> {
   public static void main(final String... args) {
     try {
       new Builder(args).build().run();
-    } catch (AttachAPINotFoundException e) {
-      System.err.println(e.getMessage());
+    } catch (AttachAPINotFoundException handled) {
+      System.err.println(handled.getMessage());
     }
   }
 
@@ -223,12 +231,13 @@ public class LocatorLauncher extends AbstractLauncher<String> {
    */
   private LocatorLauncher(final Builder builder) {
     this.command = builder.getCommand();
-    setDebug(Boolean.TRUE.equals(builder.getDebug()));
-    this.force = Boolean.TRUE.equals(builder.getForce());
     this.help = Boolean.TRUE.equals(builder.getHelp());
     this.bindAddressSpecified = builder.isBindAddressSpecified();
     this.bindAddress = builder.getBindAddress();
+    setDebug(Boolean.TRUE.equals(builder.getDebug()));
+    this.deletePidFileOnStop = Boolean.TRUE.equals(builder.getDeletePidFileOnStop());
     this.distributedSystemProperties = builder.getDistributedSystemProperties();
+    this.force = Boolean.TRUE.equals(builder.getForce());
     this.hostnameForClients = builder.getHostnameForClients();
     this.memberName = builder.getMemberName();
     this.pid = builder.getPid();
@@ -370,12 +379,9 @@ public class LocatorLauncher extends AbstractLauncher<String> {
       InetAddress localhost = SocketCreator.getLocalHost();
 
       return localhost.getCanonicalHostName();
-    } catch (UnknownHostException ignore) {
-      // TODO determine a better value for the host on which the Locator is running to return
-      // here...
+    } catch (UnknownHostException handled) {
       // NOTE returning localhost/127.0.0.1 implies the bindAddress was null and no IP address for
-      // localhost
-      // could be found
+      // localhost could be found
       return "localhost/127.0.0.1";
     }
   }
@@ -394,8 +400,9 @@ public class LocatorLauncher extends AbstractLauncher<String> {
    * 
    * @return a String value indicating the name of this Locator's log file.
    */
+  @Override
   public String getLogFileName() {
-    return StringUtils.defaultIfBlank(getMemberName(), DEFAULT_LOCATOR_LOG_NAME)
+    return defaultIfBlank(getMemberName(), DEFAULT_LOCATOR_LOG_NAME)
         .concat(DEFAULT_LOCATOR_LOG_EXT);
   }
 
@@ -405,10 +412,10 @@ public class LocatorLauncher extends AbstractLauncher<String> {
    * 
    * @return a String indicating the name of the member (this Locator) in the GemFire distributed
    *         system.
-   * @see AbstractLauncher#getMemberName()
    */
+  @Override
   public String getMemberName() {
-    return StringUtils.defaultIfBlank(this.memberName, super.getMemberName());
+    return defaultIfBlank(this.memberName, super.getMemberName());
   }
 
   /**
@@ -444,7 +451,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
    * @see #getPort()
    */
   public String getPortAsString() {
-    return ObjectUtils.defaultIfNull(getPort(), getDefaultLocatorPort()).toString();
+    return defaultIfNull(getPort(), getDefaultLocatorPort()).toString();
   }
 
   /**
@@ -463,6 +470,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
    * 
    * @return a String indicating the name for a GemFire Locator.
    */
+  @Override
   public String getServiceName() {
     return LOCATOR_SERVICE_NAME;
   }
@@ -488,14 +496,13 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     if (Command.isUnspecified(command)) {
       usage();
     } else {
-      info(StringUtils.wrap(helpMap.get(command.getName()), 80, ""));
+      info(wrap(helpMap.get(command.getName()), 80, ""));
       info("\n\nusage: \n\n");
-      info(StringUtils.wrap("> java ... " + getClass().getName() + " " + usageMap.get(command), 80,
-          "\t\t"));
+      info(wrap("> java ... " + getClass().getName() + " " + usageMap.get(command), 80, "\t\t"));
       info("\n\noptions: \n\n");
 
       for (String option : command.getOptions()) {
-        info(StringUtils.wrap("--" + option + ": " + helpMap.get(option) + "\n", 80, "\t"));
+        info(wrap("--" + option + ": " + helpMap.get(option) + "\n", 80, "\t"));
       }
 
       info("\n\n");
@@ -509,7 +516,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
    * @see #help(org.apache.geode.distributed.LocatorLauncher.Command)
    */
   public void usage() {
-    info(StringUtils.wrap(helpMap.get("launcher"), 80, "\t"));
+    info(wrap(helpMap.get("launcher"), 80, "\t"));
     info("\n\nSTART\n\n");
     help(Command.START);
     info("STATUS\n\n");
@@ -533,6 +540,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
    * @see LocatorLauncher#help(org.apache.geode.distributed.LocatorLauncher.Command)
    * @see LocatorLauncher#usage()
    */
+  @Override
   public void run() {
     if (!isHelping()) {
       switch (getCommand()) {
@@ -633,7 +641,6 @@ public class LocatorLauncher extends AbstractLauncher<String> {
               }
             });
 
-        // TODO : remove the extra param for loadFromSharedConfigDir
         try {
           this.locator = InternalLocator.startLocator(getPort(), getLogFile(), null, null, null,
               getBindAddress(), true, getDistributedSystemProperties(), getHostnameForClients());
@@ -663,10 +670,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
             LocalizedStrings.Launcher_Command_START_PID_UNAVAILABLE_ERROR_MESSAGE.toLocalizedString(
                 getServiceName(), getId(), getWorkingDirectory(), e.getMessage()),
             e);
-      } catch (Error e) {
-        failOnStart(e);
-        throw e;
-      } catch (RuntimeException e) {
+      } catch (Error | RuntimeException e) {
         failOnStart(e);
         throw e;
       } catch (Exception e) {
@@ -707,7 +711,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
       this.locator = null;
     }
     if (this.process != null) {
-      this.process.stop();
+      this.process.stop(this.deletePidFileOnStop);
       this.process = null;
     }
 
@@ -738,13 +742,10 @@ public class LocatorLauncher extends AbstractLauncher<String> {
 
       // prevent the JVM from exiting by joining the Locator Thread
       getLocator().waitToStop();
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      t = e;
-      debug(e);
-    } catch (RuntimeException e) {
-      t = e;
-      throw e;
+      t = handled;
+      debug(handled);
     } catch (Throwable e) {
       t = e;
       throw e;
@@ -789,14 +790,8 @@ public class LocatorLauncher extends AbstractLauncher<String> {
       try {
         LocatorStatusResponse response = statusLocator(getPort(), getBindAddress());
         return new LocatorState(this, Status.ONLINE, response);
-      } catch (Exception ignore) {
-        try {
-          synchronized (this) {
-            timeUnit.timedWait(this, interval);
-          }
-        } catch (InterruptedException ignoreInterrupt) {
-          // NOTE just go and send another status request to the Locator...
-        }
+      } catch (Exception handled) {
+        timedWait(interval, timeUnit);
       }
     }
 
@@ -808,6 +803,16 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     return new LocatorState(this, Status.NOT_RESPONDING);
   }
 
+  private void timedWait(final long interval, final TimeUnit timeUnit) {
+    try {
+      synchronized (this) {
+        timeUnit.timedWait(this, interval);
+      }
+    } catch (InterruptedException handled) {
+      // NOTE just go and send another status request to the Locator...
+    }
+  }
+
   /**
    * Attempts to determine the state of the Locator. The Locator's status will be in only 1 of 2
    * possible states, either ONLINE or OFFLINE. This method behaves differently depending on which
@@ -892,27 +897,18 @@ public class LocatorLauncher extends AbstractLauncher<String> {
       controller.checkPidSupport();
       final String statusJson = controller.status();
       return LocatorState.fromJson(statusJson);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to locator JVM
-      return createNoResponseState(e, "Failed to connect to locator with process id " + getPid());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
+          "Failed to connect to locator with process id " + getPid());
+    } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException
+        | TimeoutException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with locator with process id " + getPid());
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + getPid());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + getPid());
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
           "Interrupted while trying to communicate with locator with process id " + getPid());
-    } catch (TimeoutException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + getPid());
     }
   }
 
@@ -920,8 +916,8 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     try {
       LocatorStatusResponse response = statusLocator(getPort(), getBindAddress());
       return new LocatorState(this, Status.ONLINE, response);
-    } catch (Exception e) {
-      return createNoResponseState(e, "Failed to connect to locator " + getId());
+    } catch (Exception handled) {
+      return createNoResponseState(handled, "Failed to connect to locator " + getId());
     }
   }
 
@@ -930,8 +926,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     try {
       final ProcessController controller =
           new ProcessControllerFactory().createProcessController(this.controllerParameters,
-              new File(getWorkingDirectory()), ProcessType.LOCATOR.getPidFileName(),
-              READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+              new File(getWorkingDirectory()), ProcessType.LOCATOR.getPidFileName());
       parsedPid = controller.getProcessId();
 
       // note: in-process request will go infinite loop unless we do the following
@@ -944,35 +939,26 @@ public class LocatorLauncher extends AbstractLauncher<String> {
 
       final String statusJson = controller.status();
       return LocatorState.fromJson(statusJson);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to locator JVM
-      return createNoResponseState(e, "Failed to connect to locator with process id " + parsedPid);
-    } catch (FileNotFoundException e) {
+      return createNoResponseState(handled,
+          "Failed to connect to locator with process id " + parsedPid);
+    } catch (FileNotFoundException handled) {
       // could not find pid file
-      return createNoResponseState(e, "Failed to find process file "
+      return createNoResponseState(handled, "Failed to find process file "
           + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + parsedPid);
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
+    } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException
+        | TimeoutException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with locator with process id " + parsedPid);
     } catch (PidUnavailableException e) {
       // couldn't determine pid from within locator JVM
       return createNoResponseState(e, "Failed to find usable process id within file "
           + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + parsedPid);
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
           "Interrupted while trying to communicate with locator with process id " + parsedPid);
-    } catch (TimeoutException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + parsedPid);
     }
   }
 
@@ -1036,7 +1022,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     if (isStoppable()) {
       this.locator.stop();
       this.locator = null;
-      this.process.stop();
+      this.process.stop(this.deletePidFileOnStop);
       this.process = null;
       INSTANCE.compareAndSet(this, null); // note: other thread may return Status.NOT_RESPONDING now
       this.running.set(false);
@@ -1053,19 +1039,13 @@ public class LocatorLauncher extends AbstractLauncher<String> {
       controller.checkPidSupport();
       controller.stop();
       return new LocatorState(this, Status.STOPPED);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to locator JVM
-      return createNoResponseState(e, "Failed to connect to locator with process id " + getPid());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + getPid());
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + getPid());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
+          "Failed to connect to locator with process id " + getPid());
+    } catch (IOException | MBeanInvocationFailedException
+        | UnableToControlProcessException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with locator with process id " + getPid());
     }
   }
@@ -1075,8 +1055,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     try {
       final ProcessController controller =
           new ProcessControllerFactory().createProcessController(this.controllerParameters,
-              new File(getWorkingDirectory()), ProcessType.LOCATOR.getPidFileName(),
-              READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+              new File(getWorkingDirectory()), ProcessType.LOCATOR.getPidFileName());
       parsedPid = controller.getProcessId();
 
       // NOTE in-process request will go infinite loop unless we do the following
@@ -1089,49 +1068,43 @@ public class LocatorLauncher extends AbstractLauncher<String> {
 
       controller.stop();
       return new LocatorState(this, Status.STOPPED);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to locator JVM
-      return createNoResponseState(e, "Failed to connect to locator with process id " + parsedPid);
-    } catch (FileNotFoundException e) {
+      return createNoResponseState(handled,
+          "Failed to connect to locator with process id " + parsedPid);
+    } catch (FileNotFoundException handled) {
       // could not find pid file
-      return createNoResponseState(e, "Failed to find process file "
+      return createNoResponseState(handled, "Failed to find process file "
           + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
+    } catch (IOException | MBeanInvocationFailedException
+        | UnableToControlProcessException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with locator with process id " + parsedPid);
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
           "Interrupted while trying to communicate with locator with process id " + parsedPid);
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + parsedPid);
-    } catch (PidUnavailableException e) {
+    } catch (PidUnavailableException handled) {
       // couldn't determine pid from within locator JVM
-      return createNoResponseState(e, "Failed to find usable process id within file "
-          + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (TimeoutException e) {
-      return createNoResponseState(e, "Timed out trying to find usable process id within file "
+      return createNoResponseState(handled, "Failed to find usable process id within file "
           + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with locator with process id " + parsedPid);
+    } catch (TimeoutException handled) {
+      return createNoResponseState(handled,
+          "Timed out trying to find usable process id within file "
+              + ProcessType.LOCATOR.getPidFileName() + " in " + getWorkingDirectory());
     }
   }
 
   private LocatorState createNoResponseState(final Exception cause, final String errorMessage) {
     debug(cause);
-    // info(errorMessage);
     return new LocatorState(this, Status.NOT_RESPONDING, errorMessage);
   }
 
-  private Properties getOverriddenDefaults() {
+  private Properties getOverriddenDefaults() throws IOException {
     Properties overriddenDefaults = new Properties();
 
     overriddenDefaults.put(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX.concat(LOG_FILE),
-        getLogFileName());
+        getLogFile().getCanonicalPath());
 
     for (String key : System.getProperties().stringPropertyNames()) {
       if (key.startsWith(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)) {
@@ -1149,7 +1122,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     }
 
     @Override
-    public File getWorkingDirectory() {
+    public File getDirectory() {
       return new File(LocatorLauncher.this.getWorkingDirectory());
     }
 
@@ -1167,9 +1140,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     public ObjectName getNamePattern() {
       try {
         return ObjectName.getInstance("GemFire:type=Member,*");
-      } catch (MalformedObjectNameException e) {
-        return null;
-      } catch (NullPointerException e) {
+      } catch (MalformedObjectNameException | NullPointerException handled) {
         return null;
       }
     }
@@ -1210,6 +1181,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     protected static final Command DEFAULT_COMMAND = Command.UNSPECIFIED;
 
     private Boolean debug;
+    private Boolean deletePidFileOnStop;
     private Boolean force;
     private Boolean help;
     private Boolean redirectOutput;
@@ -1255,6 +1227,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
 
       parser.accepts("bind-address").withRequiredArg().ofType(String.class);
       parser.accepts("debug");
+      parser.accepts("delete-pid-file-on-stop");
       parser.accepts("dir").withRequiredArg().ofType(String.class);
       parser.accepts("force");
       parser.accepts("help");
@@ -1283,6 +1256,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
         final OptionSet options = getParser().parse(args);
 
         setDebug(options.has("debug"));
+        setDeletePidFileOnStop(options.has("delete-pid-file-on-stop"));
         setForce(options.has("force"));
         setHelp(options.has("help"));
         setRedirectOutput(options.has("redirect-output"));
@@ -1333,11 +1307,13 @@ public class LocatorLauncher extends AbstractLauncher<String> {
       // search the list of arguments for the command; technically, the command should be the first
       // argument in the
       // list, but does it really matter? stop after we find one valid command.
-      for (String arg : args) {
-        final Command command = Command.valueOfName(arg);
-        if (command != null) {
-          setCommand(command);
-          break;
+      if (args != null) {
+        for (String arg : args) {
+          final Command command = Command.valueOfName(arg);
+          if (command != null) {
+            setCommand(command);
+            break;
+          }
         }
       }
     }
@@ -1352,11 +1328,13 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see org.apache.geode.distributed.LocatorLauncher.Command#isCommand(String)
      * @see #parseArguments(String...)
      */
-    protected void parseMemberName(final String[] args) {
-      for (String arg : args) {
-        if (!(arg.startsWith(OPTION_PREFIX) || Command.isCommand(arg))) {
-          setMemberName(arg);
-          break;
+    protected void parseMemberName(final String... args) {
+      if (args != null) {
+        for (String arg : args) {
+          if (!(arg.startsWith(OPTION_PREFIX) || Command.isCommand(arg))) {
+            setMemberName(arg);
+            break;
+          }
         }
       }
     }
@@ -1369,7 +1347,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see LocatorLauncher.Command
      */
     public Command getCommand() {
-      return ObjectUtils.defaultIfNull(this.command, DEFAULT_COMMAND);
+      return defaultIfNull(this.command, DEFAULT_COMMAND);
     }
 
     /**
@@ -1401,7 +1379,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * 
      * @param debug a boolean value indicating whether debug mode is to be enabled or disabled.
      * @return this Builder instance.
-     * @see #getHelp()
+     * @see #getDebug()
      */
     public Builder setDebug(final Boolean debug) {
       this.debug = debug;
@@ -1409,6 +1387,32 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     }
 
     /**
+     * Determines whether the Geode Locator should delete the pid file when its service stops or
+     * when the JVM exits.
+     *
+     * @return a boolean value indicating if the pid file should be deleted when this service stops
+     *         or when the JVM exits.
+     * @see #setDeletePidFileOnStop(Boolean)
+     */
+    public Boolean getDeletePidFileOnStop() {
+      return this.deletePidFileOnStop;
+    }
+
+    /**
+     * Sets whether the Geode Locator should delete the pid file when its service stops or when the
+     * JVM exits.
+     *
+     * @param deletePidFileOnStop a boolean value indicating if the pid file should be deleted when
+     *        this service stops or when the JVM exits.
+     * @return this Builder instance.
+     * @see #getDeletePidFileOnStop()
+     */
+    public Builder setDeletePidFileOnStop(final Boolean deletePidFileOnStop) {
+      this.deletePidFileOnStop = deletePidFileOnStop;
+      return this;
+    }
+
+    /**
      * Gets the GemFire Distributed System (cluster) Properties configuration.
      *
      * @return a Properties object containing configuration settings for the GemFire Distributed
@@ -1425,11 +1429,10 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * 
      * @return the boolean value specifying whether or not to overwrite the PID file if it already
      *         exists.
-     * @see org.apache.geode.internal.process.LocalProcessLauncher
      * @see #setForce(Boolean)
      */
     public Boolean getForce() {
-      return ObjectUtils.defaultIfNull(this.force, DEFAULT_FORCE);
+      return defaultIfNull(this.force, DEFAULT_FORCE);
     }
 
     /**
@@ -1439,7 +1442,6 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @param force a boolean value indicating whether to overwrite the PID file when it already
      *        exists.
      * @return this Builder instance.
-     * @see org.apache.geode.internal.process.LocalProcessLauncher
      * @see #getForce()
      */
     public Builder setForce(final Boolean force) {
@@ -1513,7 +1515,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see java.net.InetAddress
      */
     public Builder setBindAddress(final String bindAddress) {
-      if (StringUtils.isBlank(bindAddress)) {
+      if (isBlank(bindAddress)) {
         this.bindAddress = null;
         return this;
       } else {
@@ -1557,7 +1559,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see #getHostnameForClients()
      */
     public Builder setHostnameForClients(final String hostnameForClients) {
-      if (StringUtils.isBlank(hostnameForClients)) {
+      if (isBlank(hostnameForClients)) {
         throw new IllegalArgumentException(
             LocalizedStrings.LocatorLauncher_Builder_INVALID_HOSTNAME_FOR_CLIENTS_ERROR_MESSAGE
                 .toLocalizedString());
@@ -1585,7 +1587,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see #getMemberName()
      */
     public Builder setMemberName(final String memberName) {
-      if (StringUtils.isBlank(memberName)) {
+      if (isBlank(memberName)) {
         throw new IllegalArgumentException(
             LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE
                 .toLocalizedString("Locator"));
@@ -1638,7 +1640,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see #setPort(Integer)
      */
     public Integer getPort() {
-      return ObjectUtils.defaultIfNull(port, getDefaultLocatorPort());
+      return defaultIfNull(port, getDefaultLocatorPort());
     }
 
     /**
@@ -1701,7 +1703,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     }
 
     boolean isWorkingDirectorySpecified() {
-      return StringUtils.isNotBlank(this.workingDirectory);
+      return isNotBlank(this.workingDirectory);
     }
 
     /**
@@ -1712,8 +1714,8 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see #setWorkingDirectory(String)
      */
     public String getWorkingDirectory() {
-      return IOUtils.tryGetCanonicalPathElseGetAbsolutePath(
-          new File(StringUtils.defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY)));
+      return tryGetCanonicalPathElseGetAbsolutePath(
+          new File(defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY)));
     }
 
     /**
@@ -1730,8 +1732,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see java.io.FileNotFoundException
      */
     public Builder setWorkingDirectory(final String workingDirectory) {
-      if (!new File(StringUtils.defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY))
-          .isDirectory()) {
+      if (!new File(defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY)).isDirectory()) {
         throw new IllegalArgumentException(
             LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
                 .toLocalizedString("Locator"),
@@ -1781,8 +1782,8 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see org.apache.geode.distributed.LocatorLauncher.Command#START
      */
     protected void validateOnStart() {
-      if (Command.START.equals(getCommand())) {
-        if (StringUtils.isBlank(getMemberName())
+      if (Command.START == getCommand()) {
+        if (isBlank(getMemberName())
             && !isSet(System.getProperties(), DistributionConfig.GEMFIRE_PREFIX + NAME)
             && !isSet(getDistributedSystemProperties(), NAME)
             && !isSet(loadGemFireProperties(DistributedSystem.getPropertyFileURL()), NAME)) {
@@ -1791,7 +1792,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
                   .toLocalizedString("Locator"));
         }
 
-        if (!SystemUtils.CURRENT_DIRECTORY.equals(getWorkingDirectory())) {
+        if (!CURRENT_DIRECTORY.equals(getWorkingDirectory())) {
           throw new IllegalStateException(
               LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE
                   .toLocalizedString("Locator"));
@@ -1805,7 +1806,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see org.apache.geode.distributed.LocatorLauncher.Command#STATUS
      */
     protected void validateOnStatus() {
-      if (Command.STATUS.equals(getCommand())) {
+      if (Command.STATUS == getCommand()) {
       }
     }
 
@@ -1815,7 +1816,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see org.apache.geode.distributed.LocatorLauncher.Command#STOP
      */
     protected void validateOnStop() {
-      if (Command.STOP.equals(getCommand())) {
+      if (Command.STOP == getCommand()) {
       }
     }
 
@@ -1848,8 +1849,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
     private final String name;
 
     Command(final String name, final String... options) {
-      assert !StringUtils
-          .isBlank(name) : "The name of the locator launcher command must be specified!";
+      assert isNotBlank(name) : "The name of the locator launcher command must be specified!";
       this.name = name;
       this.options = (options != null ? Collections.unmodifiableList(Arrays.asList(options))
           : Collections.<String>emptyList());
@@ -1925,7 +1925,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      *         option.
      */
     public boolean hasOption(final String option) {
-      return getOptions().contains(StringUtils.lowerCase(option));
+      return getOptions().contains(lowerCase(option));
     }
 
     /**
@@ -1935,7 +1935,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
      * @see #UNSPECIFIED
      */
     public boolean isUnspecified() {
-      return UNSPECIFIED.equals(this);
+      return UNSPECIFIED == this;
     }
 
     /**
@@ -2033,7 +2033,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
         final InternalLocator locator = InternalLocator.getLocator();
         final InetAddress bindAddress = locator.getBindAddress();
         if (bindAddress != null) {
-          if (StringUtils.isBlank(bindAddress.getHostAddress())) {
+          if (isBlank(bindAddress.getHostAddress())) {
             return bindAddress.getHostAddress();
           }
         }
@@ -2047,10 +2047,9 @@ public class LocatorLauncher extends AbstractLauncher<String> {
         final File logFile = locator.getLogFile();
 
         if (logFile != null && logFile.isFile()) {
-          final String logFileCanonicalPath =
-              IOUtils.tryGetCanonicalPathElseGetAbsolutePath(logFile);
-          if (StringUtils.isNotBlank(logFileCanonicalPath)) { // this is probably not need but a
-                                                              // safe
+          final String logFileCanonicalPath = tryGetCanonicalPathElseGetAbsolutePath(logFile);
+          if (isNotBlank(logFileCanonicalPath)) { // this is probably not need but a
+                                                  // safe
             // check none-the-less.
             return logFileCanonicalPath;
           }
@@ -2063,7 +2062,7 @@ public class LocatorLauncher extends AbstractLauncher<String> {
       if (InternalLocator.hasLocator()) {
         final InternalLocator locator = InternalLocator.getLocator();
         final String portAsString = String.valueOf(locator.getPort());
-        if (StringUtils.isNotBlank(portAsString)) {
+        if (isNotBlank(portAsString)) {
           return portAsString;
         }
       }


[14/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTest.java
index d525be2..29ddaaf 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTest.java
@@ -14,973 +14,327 @@
  */
 package org.apache.geode.distributed;
 
-import static org.apache.geode.distributed.ConfigurationProperties.*;
+import static org.apache.geode.distributed.AbstractLauncher.Status.NOT_RESPONDING;
+import static org.apache.geode.distributed.AbstractLauncher.Status.ONLINE;
+import static org.apache.geode.distributed.AbstractLauncher.Status.STOPPED;
+import static org.apache.geode.distributed.ConfigurationProperties.DISABLE_AUTO_RECONNECT;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+import java.net.BindException;
+import java.net.InetAddress;
+import java.util.Collections;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import org.apache.geode.cache.Cache;
-import org.apache.geode.cache.DataPolicy;
-import org.apache.geode.cache.Scope;
-import org.apache.geode.distributed.AbstractLauncher.Status;
 import org.apache.geode.distributed.ServerLauncher.Builder;
 import org.apache.geode.distributed.ServerLauncher.ServerState;
-import org.apache.geode.internal.AvailablePort;
-import org.apache.geode.internal.AvailablePortHelper;
 import org.apache.geode.internal.GemFireVersion;
-import org.apache.geode.internal.cache.AbstractCacheServer;
-import org.apache.geode.internal.cache.xmlcache.CacheCreation;
-import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator;
-import org.apache.geode.internal.cache.xmlcache.RegionAttributesCreation;
-import org.apache.geode.internal.net.SocketCreatorFactory;
 import org.apache.geode.internal.process.ProcessControllerFactory;
 import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.internal.security.SecurableCommunicationChannel;
 import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.PrintWriter;
-import java.lang.management.ManagementFactory;
-import java.net.BindException;
-import java.net.InetAddress;
-
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.*;
 
 /**
- * Integration tests for ServerLauncher as a local API in the local JVM.
+ * Integration tests for using {@link ServerLauncher} as an in-process API within an existing JVM.
  *
- * @see org.apache.geode.distributed.AbstractLauncher
- * @see org.apache.geode.distributed.ServerLauncher
- * @see org.apache.geode.distributed.ServerLauncher.Builder
- * @see org.apache.geode.distributed.ServerLauncher.ServerState
- * @see org.apache.geode.internal.AvailablePortHelper
  * @since GemFire 8.0
  */
 @Category(IntegrationTest.class)
-public class ServerLauncherLocalIntegrationTest extends AbstractServerLauncherIntegrationTestCase {
+public class ServerLauncherLocalIntegrationTest extends ServerLauncherLocalIntegrationTestCase {
 
   @Before
-  public final void setUpServerLauncherLocalTest() throws Exception {
+  public void setUpServerLauncherLocalIntegrationTest() throws Exception {
     disconnectFromDS();
-    System.setProperty(ProcessType.TEST_PREFIX_PROPERTY, getUniqueName() + "-");
+    System.setProperty(ProcessType.PROPERTY_TEST_PREFIX, getUniqueName() + "-");
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isTrue();
   }
 
   @After
-  public final void tearDownServerLauncherLocalTest() throws Exception {
+  public void tearDownServerLauncherLocalIntegrationTest() throws Exception {
     disconnectFromDS();
   }
 
-  protected Status getExpectedStopStatusForNotRunning() {
-    return Status.NOT_RESPONDING;
+  @Test
+  public void usesLocatorPortAsDefaultPort() throws Exception {
+    launcher = givenServerLauncher();
+
+    assertThat(launcher.getServerPort()).isEqualTo(defaultServerPort);
   }
 
   @Test
-  public void testBuilderSetProperties() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
+  public void startReturnsOnline() throws Exception {
+    launcher = givenServerLauncher();
 
-    this.launcher = new Builder().setDisableDefaultServer(true).setForce(true)
-        .setMemberName(getUniqueName()).setWorkingDirectory(rootFolder)
-        .set(DISABLE_AUTO_RECONNECT, "true").set(LOG_LEVEL, "config").set(MCAST_PORT, "0").build();
+    assertThat(launcher.start().getStatus()).isEqualTo(ONLINE);
+  }
 
-    assertNotNull(this.launcher);
+  @Test
+  public void startWithPortUsesPort() throws Exception {
+    ServerLauncher launcher =
+        startServer(newBuilder().setDisableDefaultServer(false).setServerPort(defaultServerPort));
 
-    try {
-      assertEquals(Status.ONLINE, this.launcher.start().getStatus());
-      waitForServerToStart(this.launcher);
+    assertThat(launcher.getCache().getCacheServers().get(0).getPort()).isEqualTo(defaultServerPort);
+  }
 
-      final Cache cache = this.launcher.getCache();
+  @Test
+  public void startWithPortZeroUsesAnEphemeralPort() throws Exception {
+    ServerLauncher launcher =
+        startServer(newBuilder().setDisableDefaultServer(false).setServerPort(0));
 
-      assertNotNull(cache);
+    assertThat(launcher.getCache().getCacheServers().get(0).getPort()).isGreaterThan(0);
+  }
 
-      final DistributedSystem distributedSystem = cache.getDistributedSystem();
+  @Test
+  public void startUsesBuilderValues() throws Exception {
+    ServerLauncher launcher = startServer(newBuilder().set(DISABLE_AUTO_RECONNECT, "true"));
+
+    Cache cache = launcher.getCache();
+    assertThat(cache).isNotNull();
+
+    DistributedSystem system = cache.getDistributedSystem();
+    assertThat(system).isNotNull();
+    assertThat(system.getProperties().getProperty(DISABLE_AUTO_RECONNECT)).isEqualTo("true");
+    assertThat(system.getProperties().getProperty(LOG_LEVEL)).isEqualTo("config");
+    assertThat(system.getProperties().getProperty(MCAST_PORT)).isEqualTo("0");
+    assertThat(system.getProperties().getProperty(NAME)).isEqualTo(getUniqueName());
+  }
 
-      assertNotNull(distributedSystem);
-      assertEquals("true", distributedSystem.getProperties().getProperty(DISABLE_AUTO_RECONNECT));
-      assertEquals("config", distributedSystem.getProperties().getProperty(LOG_LEVEL));
-      assertEquals("0", distributedSystem.getProperties().getProperty(MCAST_PORT));
-      assertEquals(getUniqueName(), distributedSystem.getProperties().getProperty(NAME));
+  @Test
+  public void startCreatesPidFile() throws Exception {
+    startServer();
 
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThat(getPidFile()).exists();
+  }
+
+  @Test
+  public void pidFileContainsServerPid() throws Exception {
+    startServer();
 
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      assertNull(this.launcher.getCache());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThat(getServerPid()).isEqualTo(localPid);
   }
 
   @Test
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertTrue(factory.isAttachAPIFound());
+  public void startDeletesStaleControlFiles() throws Exception {
+    File stopRequestFile = givenControlFile(getProcessType().getStopRequestFileName());
+    File statusRequestFile = givenControlFile(getProcessType().getStatusRequestFileName());
+    File statusFile = givenControlFile(getProcessType().getStatusFileName());
+
+    startServer();
+
+    assertDeletionOf(stopRequestFile);
+    assertDeletionOf(statusRequestFile);
+    assertDeletionOf(statusFile);
   }
 
   @Test
-  public void testStartCreatesPidFile() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // build and start the Server locally
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    this.launcher = builder.build();
-    assertNotNull(this.launcher);
-
-    try {
-      this.launcher.start();
-      waitForServerToStart(this.launcher);
-      assertEquals(Status.ONLINE, this.launcher.status().getStatus());
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      assertEquals(Status.ONLINE, this.launcher.status().getStatus());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startOverwritesStalePidFile() throws Exception {
+    givenPidFile(fakePid);
+
+    startServer();
+
+    assertThat(getServerPid()).isNotEqualTo(fakePid);
   }
 
   @Test
-  public void testStartDeletesStaleControlFiles() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // create existing control files
-    this.stopRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getStopRequestFileName());
-    this.stopRequestFile.createNewFile();
-    assertTrue(this.stopRequestFile.exists());
-
-    this.statusRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getStatusRequestFileName());
-    this.statusRequestFile.createNewFile();
-    assertTrue(this.statusRequestFile.exists());
-
-    this.statusFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getStatusFileName());
-    this.statusFile.createNewFile();
-    assertTrue(this.statusFile.exists());
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-    this.launcher.start();
-
-    try {
-      waitForServerToStart(this.launcher);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      // validate stale control files were deleted
-      assertFalse(this.stopRequestFile.exists());
-      assertFalse(this.statusRequestFile.exists());
-      assertFalse(this.statusFile.exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithDisableDefaultServerDoesNotUseDefaultPort() throws Exception {
+    givenServerPortIsFree(defaultServerPort);
+
+    startServer(withDisableDefaultServer());
+
+    assertThatServerPortIsFree(defaultServerPort);
   }
 
   @Test
-  public void testStartOverwritesStalePidFile() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // create existing pid file
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-    assertFalse("Integer.MAX_VALUE shouldn't be the same as local pid " + Integer.MAX_VALUE,
-        Integer.MAX_VALUE == ProcessUtils.identifyPid());
-    writePid(this.pidFile, Integer.MAX_VALUE);
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-    this.launcher.start();
-
-    try {
-      waitForServerToStart(this.launcher);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // validate the pid file and its contents
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithDisableDefaultServerSucceedsWhenDefaultPortInUse() throws Exception {
+    givenServerPortInUse(defaultServerPort);
+
+    startServer(withDisableDefaultServer());
+
+    assertThatServerPortIsInUseBySocket(defaultServerPort);
   }
 
-  /**
-   * Confirms fix for #47778.
-   */
   @Test
-  public void testStartUsingDisableDefaultServerLeavesPortFree() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // build and start the server
-    assertTrue(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    this.launcher = builder.build();
-
-    // wait for server to start
-    try {
-      // if start succeeds without throwing exception then #47778 is fixed
-      this.launcher.start();
-      waitForServerToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      // verify server did not a port
-      assertTrue(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-      final ServerState status = this.launcher.status();
-      final String portString = status.getPort();
-      assertEquals("Port should be \"\" instead of " + portString, "", portString);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithServerPortOverridesPortInCacheXml() throws Exception {
+    int[] freePorts = getRandomAvailableTCPPorts(2);
+    int cacheXmlPort = freePorts[0];
+    int startPort = freePorts[1];
+    givenCacheXmlFileWithServerPort(cacheXmlPort);
+
+    launcher = startServer(new Builder().setServerPort(startPort));
+
+    // server should use --server-port instead of port in cache.xml
+    assertThatServerPortIsInUse(startPort);
+    assertThatServerPortIsFree(cacheXmlPort);
+    assertThat(Integer.valueOf(launcher.status().getPort())).isEqualTo(startPort);
   }
 
-  /**
-   * Confirms fix for #47778.
-   */
   @Test
-  public void testStartUsingDisableDefaultServerSkipsPortCheck() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // generate one free port and then use TEST_OVERRIDE_DEFAULT_PORT_PROPERTY
-    this.socket = SocketCreatorFactory
-        .createNonDefaultInstance(false, false, null, null, System.getProperties())
-        .createServerSocket(this.serverPort, 50, null, -1);
-    assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    this.launcher = builder.build();
-
-    // wait for server to start
-    try {
-      // if start succeeds without throwing exception then #47778 is fixed
-      this.launcher.start();
-      waitForServerToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      final ServerState status = this.launcher.status();
-      final String portString = status.getPort();
-      assertEquals("Port should be \"\" instead of " + portString, "", portString);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // verify port is still in use
-    this.errorCollector.checkThat(
-        AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET), is(equalTo(false)));
+  public void startWithServerPortOverridesDefaultWithCacheXml() throws Exception {
+    givenCacheXmlFile();
+
+    launcher = awaitStart(new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
+        .setServerPort(defaultServerPort).setWorkingDirectory(getWorkingDirectoryPath())
+        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0"));
+
+    // verify server used --server-port instead of default
+    assertThatServerPortIsInUse(defaultServerPort);
+    assertThat(Integer.valueOf(launcher.status().getPort())).isEqualTo(defaultServerPort);
   }
 
   @Test
-  @Ignore("Need to rewrite this without using dunit.Host")
-  public void testStartUsingForceOverwritesExistingPidFile()
-      throws Throwable {}/*
-                          * assertTrue(getUniqueName() + " is broken if PID == Integer.MAX_VALUE",
-                          * ProcessUtils.identifyPid() != Integer.MAX_VALUE);
-                          * 
-                          * // create existing pid file this.pidFile = new
-                          * File(ProcessType.SERVER.getPidFileName()); final int realPid =
-                          * Host.getHost(0).getVM(3).invoke(() -> ProcessUtils.identifyPid());
-                          * assertFalse(realPid == ProcessUtils.identifyPid());
-                          * writePid(this.pidFile, realPid);
-                          * 
-                          * // build and start the server final Builder builder = new Builder()
-                          * .setDisableDefaultServer(true) .setForce(true)
-                          * .setMemberName(getUniqueName()) .setRedirectOutput(true)
-                          * .set(DistributionConfig.ConfigurationProperties.MCAST_PORT, "0");
-                          * 
-                          * assertTrue(builder.getForce()); this.launcher = builder.build();
-                          * assertTrue(this.launcher.isForcing()); this.launcher.start();
-                          * 
-                          * // collect and throw the FIRST failure Throwable failure = null;
-                          * 
-                          * try { waitForServerToStart(this.launcher);
-                          * 
-                          * // validate the pid file and its contents
-                          * assertTrue(this.pidFile.exists()); final int pid =
-                          * readPid(this.pidFile); assertTrue(pid > 0);
-                          * assertTrue(ProcessUtils.isProcessAlive(pid));
-                          * assertIndexDetailsEquals(getPid(), pid);
-                          * 
-                          * // validate log file was created final String logFileName =
-                          * getUniqueName()+".log"; assertTrue("Log file should exist: " +
-                          * logFileName, new File(logFileName).exists());
-                          * 
-                          * } catch (Throwable e) { logger.error(e); if (failure == null) { failure
-                          * = e; } }
-                          * 
-                          * try { assertIndexDetailsEquals(Status.STOPPED,
-                          * this.launcher.stop().getStatus()); waitForFileToDelete(this.pidFile); }
-                          * catch (Throwable e) { logger.error(e); if (failure == null) { failure =
-                          * e; } }
-                          * 
-                          * if (failure != null) { throw failure; } } //
-                          * testStartUsingForceOverwritesExistingPidFile
-                          */
+  public void startWithDefaultPortInUseFailsWithBindException() throws Exception {
+    givenServerPortInUse(defaultServerPort);
+
+    launcher = new Builder().build();
+
+    assertThatThrownBy(() -> launcher.start()).isInstanceOf(RuntimeException.class)
+        .hasCauseInstanceOf(BindException.class);
+  }
 
-  /**
-   * Confirms part of fix for #47664
-   */
   @Test
-  public void testStartUsingServerPortOverridesCacheXml() throws Throwable {
-    // verifies part of the fix for #47664
-
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // generate two free ports
-    final int[] freeTCPPorts = AvailablePortHelper.getRandomAvailableTCPPorts(2);
-    assertTrue(AvailablePort.isPortAvailable(freeTCPPorts[0], AvailablePort.SOCKET));
-    assertTrue(AvailablePort.isPortAvailable(freeTCPPorts[1], AvailablePort.SOCKET));
-
-    // write out cache.xml with one port
-    final CacheCreation creation = new CacheCreation();
-    final RegionAttributesCreation attrs = new RegionAttributesCreation(creation);
-    attrs.setScope(Scope.DISTRIBUTED_ACK);
-    attrs.setDataPolicy(DataPolicy.REPLICATE);
-    creation.createRegion(getUniqueName(), attrs);
-    creation.addCacheServer().setPort(freeTCPPorts[0]);
-
-    File cacheXmlFile = this.temporaryFolder.newFile(getUniqueName() + ".xml");
-    final PrintWriter pw = new PrintWriter(new FileWriter(cacheXmlFile), true);
-    CacheXmlGenerator.generate(creation, pw);
-    pw.close();
-
-    System.setProperty(CACHE_XML_FILE, cacheXmlFile.getCanonicalPath());
-
-    // start server
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
-        .setServerPort(freeTCPPorts[1]).setWorkingDirectory(rootFolder).set(LOG_LEVEL, "config")
-        .set(MCAST_PORT, "0");
-
-    this.launcher = builder.build();
-    this.launcher.start();
-
-    // wait for server to start up
-    try {
-      waitForServerToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      // verify server used --server-port instead of default or port in cache.xml
-      assertTrue(AvailablePort.isPortAvailable(freeTCPPorts[0], AvailablePort.SOCKET));
-      assertFalse(AvailablePort.isPortAvailable(freeTCPPorts[1], AvailablePort.SOCKET));
-
-      final ServerState status = this.launcher.status();
-      final String portString = status.getPort();
-      final int port = Integer.valueOf(portString);
-      assertEquals("Port should be " + freeTCPPorts[1] + " instead of " + port, freeTCPPorts[1],
-          port);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-      assertFalse("PID file still exists!", pidFile.exists());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithServerPortInUseFailsWithBindException() throws Exception {
+    givenServerPortInUse(nonDefaultServerPort);
+
+    launcher = new Builder().setServerPort(nonDefaultServerPort).build();
+
+    assertThatThrownBy(() -> launcher.start()).isInstanceOf(RuntimeException.class)
+        .hasCauseInstanceOf(BindException.class);
+  }
+
+  @Test
+  public void statusForDisableDefaultServerHasEmptyPort() throws Exception {
+    givenServerPortIsFree(defaultServerPort);
+
+    ServerState serverState = startServer(newBuilder().setDisableDefaultServer(true)).status();
+
+    assertThat(serverState.getPort()).isEqualTo("");
+  }
+
+  @Test
+  public void statusWithPidReturnsOnlineWithDetails() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState = new Builder().setPid(localPid).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(ONLINE);
+    assertThat(serverState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(serverState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(serverState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(serverState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(serverState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(serverState.getLogFile()).isEqualTo(getLogFilePath());
+    assertThat(serverState.getMemberName()).isEqualTo(getUniqueName());
+    assertThat(serverState.getPid().intValue()).isEqualTo(localPid);
+    assertThat(serverState.getUptime()).isGreaterThan(0);
+    assertThat(serverState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
-  /**
-   * Confirms part of fix for #47664
-   */
   @Test
-  public void testStartUsingServerPortUsedInsteadOfDefaultCacheXml() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // write out cache.xml with one port
-    final CacheCreation creation = new CacheCreation();
-    final RegionAttributesCreation attrs = new RegionAttributesCreation(creation);
-    attrs.setScope(Scope.DISTRIBUTED_ACK);
-    attrs.setDataPolicy(DataPolicy.REPLICATE);
-    creation.createRegion(getUniqueName(), attrs);
-    creation.addCacheServer();
-
-    File cacheXmlFile = this.temporaryFolder.newFile(getUniqueName() + ".xml");
-    final PrintWriter pw = new PrintWriter(new FileWriter(cacheXmlFile), true);
-    CacheXmlGenerator.generate(creation, pw);
-    pw.close();
-
-    System.setProperty(CACHE_XML_FILE, cacheXmlFile.getCanonicalPath());
-
-    // start server
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
-        .setServerPort(this.serverPort).setWorkingDirectory(rootFolder).set(LOG_LEVEL, "config")
-        .set(MCAST_PORT, "0");
-
-    this.launcher = builder.build();
-    this.launcher.start();
-
-    // wait for server to start up
-    try {
-      waitForServerToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      // verify server used --server-port instead of default
-      assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-      final int port = Integer.valueOf(this.launcher.status().getPort());
-      assertEquals("Port should be " + this.serverPort + " instead of " + port, this.serverPort,
-          port);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void statusWithWorkingDirectoryReturnsOnlineWithDetails() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(ONLINE);
+    assertThat(serverState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(serverState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(serverState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(serverState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(serverState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(serverState.getLogFile()).isEqualTo(getLogFilePath());
+    assertThat(serverState.getMemberName()).isEqualTo(getUniqueName());
+    assertThat(serverState.getPid().intValue()).isEqualTo(readPidFile());
+    assertThat(serverState.getUptime()).isGreaterThan(0);
+    assertThat(serverState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
   @Test
-  public void testStartWithDefaultPortInUseFails() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // generate one free port and then use TEST_OVERRIDE_DEFAULT_PORT_PROPERTY
-    this.socket =
-        SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER)
-            .createServerSocket(this.serverPort, 50, null, -1);
-    assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-    // build and start the server
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
-        .setWorkingDirectory(rootFolder).set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    this.launcher = builder.build();
-
-    RuntimeException expected = null;
-    try {
-      this.launcher.start();
-
-      // why did it not fail like it's supposed to?
-      final String property =
-          System.getProperty(AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY);
-      assertNotNull(property);
-      assertEquals(this.serverPort, Integer.valueOf(property).intValue());
-      assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-      fail("Server port is " + this.launcher.getCache().getCacheServers().get(0).getPort());
-      fail("ServerLauncher start should have thrown RuntimeException caused by BindException");
-    } catch (RuntimeException e) {
-      expected = e;
-      assertNotNull(expected.getMessage());
-      // BindException text varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertNotNull(expected);
-      final Throwable cause = expected.getCause();
-      assertNotNull(cause);
-      assertTrue(cause instanceof BindException);
-      // BindException string varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertFalse("Pid file should not exist: " + this.pidFile, this.pidFile.exists());
-
-      // creation of log file seems to be random -- look into why sometime
-      final String logFileName = getUniqueName() + ".log";
-      assertFalse("Log file should not exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // just in case the launcher started...
-    ServerState status = null;
-    try {
-      status = this.launcher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
-
-    try {
-      waitForFileToDelete(this.pidFile);
-      assertEquals(getExpectedStopStatusForNotRunning(), status.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void statusWithEmptyPidFileThrowsIllegalArgumentException() throws Exception {
+    givenEmptyPidFile();
+
+    ServerLauncher launcher = new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build();
+
+    assertThatThrownBy(() -> launcher.status()).isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid pid 'null' found in");
   }
 
   @Test
-  @Ignore("Need to rewrite this without using dunit.Host")
-  public void testStartWithExistingPidFileFails()
-      throws Throwable {}/*
-                          * // create existing pid file final int realPid =
-                          * Host.getHost(0).getVM(3).invoke(() -> ProcessUtils.identifyPid());
-                          * assertFalse("Remote pid shouldn't be the same as local pid " + realPid,
-                          * realPid == ProcessUtils.identifyPid());
-                          * 
-                          * this.pidFile = new File(ProcessType.SERVER.getPidFileName());
-                          * writePid(this.pidFile, realPid);
-                          * 
-                          * // build and start the server final Builder builder = new Builder()
-                          * .setDisableDefaultServer(true) .setMemberName(getUniqueName())
-                          * .setRedirectOutput(true) .set(logLevel, "config")
-                          * .set(DistributionConfig.ConfigurationProperties.MCAST_PORT, "0");
-                          * 
-                          * assertFalse(builder.getForce()); this.launcher = builder.build();
-                          * assertFalse(this.launcher.isForcing());
-                          * 
-                          * // collect and throw the FIRST failure Throwable failure = null;
-                          * RuntimeException expected = null;
-                          * 
-                          * try { this.launcher.start();
-                          * fail("ServerLauncher start should have thrown RuntimeException caused by FileAlreadyExistsException"
-                          * ); } catch (RuntimeException e) { expected = e;
-                          * assertNotNull(expected.getMessage()); assertTrue(expected.getMessage().
-                          * contains("A PID file already exists and a Server may be running in")); }
-                          * catch (Throwable e) { logger.error(e); if (failure == null) { failure =
-                          * e; } }
-                          * 
-                          * // just in case the launcher started... ServerState status = null; try {
-                          * status = this.launcher.stop(); } catch (Throwable t) { // ignore }
-                          * 
-                          * try { assertNotNull(expected); final Throwable cause =
-                          * expected.getCause(); assertNotNull(cause); assertTrue(cause instanceof
-                          * FileAlreadyExistsException);
-                          * assertTrue(cause.getMessage().contains("Pid file already exists: "));
-                          * assertTrue(cause.getMessage().contains("vf.gf.server.pid for process " +
-                          * realPid)); } catch (Throwable e) { logger.error(e); if (failure == null)
-                          * { failure = e; } }
-                          * 
-                          * try { delete(this.pidFile); final Status theStatus = status.getStatus();
-                          * assertFalse(theStatus == Status.STARTING); assertFalse(theStatus ==
-                          * Status.ONLINE); } catch (Throwable e) { logger.error(e); if (failure ==
-                          * null) { failure = e; } }
-                          * 
-                          * if (failure != null) { throw failure; } } //
-                          * testStartWithExistingPidFileFails
-                          */
+  public void statusWithEmptyWorkingDirectoryReturnsNotRespondingWithDetails() throws Exception {
+    givenEmptyWorkingDirectory();
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(NOT_RESPONDING);
+    assertThat(serverState.getClasspath()).isNull();
+    assertThat(serverState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(serverState.getHost()).isNull();
+    assertThat(serverState.getJavaVersion()).isNull();
+    assertThat(serverState.getJvmArguments()).isEqualTo(Collections.emptyList());
+    assertThat(serverState.getLogFile()).isNull();
+    assertThat(serverState.getMemberName()).isNull();
+    assertThat(serverState.getPid()).isNull();
+    assertThat(serverState.getUptime().intValue()).isEqualTo(0);
+    assertThat(serverState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
+  }
 
   /**
-   * Confirms fix for #47665.
+   * This test takes > 1 minute to run in {@link ServerLauncherLocalFileIntegrationTest}.
    */
   @Test
-  public void testStartUsingServerPortInUseFails() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // generate one free port and then use TEST_OVERRIDE_DEFAULT_PORT_PROPERTY
-    final int freeTCPPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);
-    this.socket =
-        SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER)
-            .createServerSocket(freeTCPPort, 50, null, -1);
-
-    // build and start the server
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
-        .setServerPort(freeTCPPort).setWorkingDirectory(rootFolder).set(LOG_LEVEL, "config")
-        .set(MCAST_PORT, "0");
-
-    this.launcher = builder.build();
-
-    RuntimeException expected = null;
-    try {
-      this.launcher.start();
-      fail("ServerLauncher start should have thrown RuntimeException caused by BindException");
-    } catch (RuntimeException e) {
-      expected = e;
-      assertNotNull(expected.getMessage());
-      // BindException string varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertNotNull(expected);
-      final Throwable cause = expected.getCause();
-      assertNotNull(cause);
-      assertTrue(cause instanceof BindException);
-      // BindException string varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertFalse("Pid file should not exist: " + this.pidFile, this.pidFile.exists());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // just in case the launcher started...
-    ServerState status = null;
-    try {
-      status = this.launcher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
-
-    try {
-      waitForFileToDelete(this.pidFile);
-      assertEquals(getExpectedStopStatusForNotRunning(), status.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void statusWithStalePidFileReturnsNotResponding() throws Exception {
+    givenPidFile(fakePid);
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(NOT_RESPONDING);
   }
 
   @Test
-  public void testStatusUsingPid() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    ServerLauncher pidLauncher = null;
-    try {
-      this.launcher.start();
-      waitForServerToStart(this.launcher);
-
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      pidLauncher = new Builder().setPid(pid).build();
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      final ServerState actualStatus = pidLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      // getWorkingDirectory returns user.dir instead of rootFolder because test is starting Server
-      // in this process (to move logFile and pidFile into temp dir)
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    if (pidLauncher == null) {
-      try {
-        assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-
-    } else {
-      try {
-        assertEquals(Status.STOPPED, pidLauncher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-    }
+  public void stopWithPidReturnsStopped() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState = new Builder().setPid(localPid).build().stop();
+
+    assertThat(serverState.getStatus()).isEqualTo(STOPPED);
   }
 
   @Test
-  public void testStatusUsingWorkingDirectory() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    ServerLauncher dirLauncher = null;
-    try {
-      this.launcher.start();
-      waitForServerToStart(this.launcher);
-
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      dirLauncher = new Builder().setWorkingDirectory(rootFolder).build();
-      assertNotNull(dirLauncher);
-      assertFalse(dirLauncher.isRunning());
-
-      final ServerState actualStatus = dirLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      // getWorkingDirectory returns user.dir instead of rootFolder because test is starting Server
-      // in this process (to move logFile and pidFile into temp dir)
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    if (dirLauncher == null) {
-      try {
-        assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-
-    } else {
-      try {
-        assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-    }
+  public void stopWithPidDeletesPidFile() throws Exception {
+    givenRunningServer(newBuilder().setDeletePidFileOnStop(true));
+
+    new Builder().setPid(localPid).build().stop();
+
+    assertDeletionOf(getPidFile());
   }
 
   @Test
-  public void testStopUsingPid() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    ServerLauncher pidLauncher = null;
-
-    try {
-      this.launcher.start();
-      waitForServerToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      pidLauncher = new Builder().setPid(pid).build();
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      // stop the server
-      final ServerState serverState = pidLauncher.stop();
-      assertNotNull(serverState);
-      assertEquals(Status.STOPPED, serverState.getStatus());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.launcher.stop();
-    } catch (Throwable e) {
-      // ignore
-    }
-
-    try {
-      // verify the PID file was deleted
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void stopWithWorkingDirectoryReturnsStopped() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertThat(serverState.getStatus()).isEqualTo(STOPPED);
   }
 
   @Test
-  public void testStopUsingWorkingDirectory() throws Throwable {
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // build and start the server
-    final Builder builder = new Builder().setDisableDefaultServer(true)
-        .setMemberName(getUniqueName()).setRedirectOutput(true).setWorkingDirectory(rootFolder)
-        .set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    ServerLauncher dirLauncher = null;
-    try {
-      this.launcher.start();
-      waitForServerToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      dirLauncher = new Builder().setWorkingDirectory(rootFolder).build();
-      assertNotNull(dirLauncher);
-      assertFalse(dirLauncher.isRunning());
-
-      // stop the server
-      final ServerState serverState = dirLauncher.stop();
-      assertNotNull(serverState);
-      assertEquals(Status.STOPPED, serverState.getStatus());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.launcher.stop();
-    } catch (Throwable e) {
-      // ignore
-    }
-
-    try {
-      // verify the PID file was deleted
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void stopWithWorkingDirectoryDeletesPidFile() throws Exception {
+    givenRunningServer(newBuilder().setDeletePidFileOnStop(true));
+
+    new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertDeletionOf(getPidFile());
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTestCase.java
new file mode 100644
index 0000000..917b529
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalIntegrationTestCase.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+public class ServerLauncherLocalIntegrationTestCase extends ServerLauncherIntegrationTestCase {
+
+  protected ServerLauncher.Builder withDisableDefaultServer() {
+    return withDisableDefaultServer(true);
+  }
+
+  protected ServerLauncher.Builder withDisableDefaultServer(final boolean value) {
+    return newBuilder().setDisableDefaultServer(value);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteFileIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteFileIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteFileIntegrationTest.java
index 5348b28..7b94e6f 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteFileIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteFileIntegrationTest.java
@@ -14,29 +14,21 @@
  */
 package org.apache.geode.distributed;
 
-import static org.junit.Assert.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.distributed.AbstractLauncher.Status;
 import org.apache.geode.distributed.ServerLauncher.Builder;
 import org.apache.geode.internal.process.ProcessControllerFactory;
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
 import org.apache.geode.lang.AttachAPINotFoundException;
 import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
- * Subclass of ServerLauncherRemoteDUnitTest which forces the code to not find the Attach API which
- * is in the JDK tools.jar. As a result ServerLauncher ends up using the FileProcessController
+ * Subclass of {@link ServerLauncherLocalIntegrationTest} which forces the code to not find the
+ * Attach API. As a result {@link ServerLauncher} ends up using the FileProcessController
  * implementation.
  * 
  * @since GemFire 8.0
@@ -47,179 +39,54 @@ public class ServerLauncherRemoteFileIntegrationTest extends ServerLauncherRemot
   @Before
   public void setUpServerLauncherRemoteFileTest() throws Exception {
     System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true");
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isFalse();
   }
 
-  @After
-  public void tearDownServerLauncherRemoteFileTest() throws Exception {}
-
-  @Override
-  @Test
   /**
-   * Override and assert Attach API is NOT found
+   * Override to assert that STATUS with --pid throws AttachAPINotFoundException
    */
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertFalse(factory.isAttachAPIFound());
-  }
-
   @Override
   @Test
-  /**
-   * Override because FileProcessController cannot request status with PID
-   */
-  public void testStatusUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
+  public void statusWithPidReturnsOnlineWithDetails() throws Exception {
+    givenRunningServer();
 
-    // wait for server to start
-    int pid = 0;
-    ServerLauncher pidLauncher = null;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
-
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      // status with pid only should throw AttachAPINotFoundException
-      try {
-        pidLauncher.status();
-        fail("FileProcessController should have thrown AttachAPINotFoundException");
-      } catch (AttachAPINotFoundException e) {
-        // passed
-      }
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid, true);
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    } finally {
-      new File(ProcessType.SERVER.getStatusRequestFileName()).delete(); // TODO: delete
-    }
+    assertThatThrownBy(() -> new Builder().setPid(getServerPid()).build().status())
+        .isInstanceOf(AttachAPINotFoundException.class);
   }
 
-  @Override
-  @Test
   /**
-   * Override because FileProcessController cannot request stop with PID
+   * Override to assert that STOP with --pid throws AttachAPINotFoundException
    */
-  public void testStopUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(createLoggingListener("sysout", getUniqueName() + "#sysout")).build()
-            .start();
-    this.processErrReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(createLoggingListener("syserr", getUniqueName() + "#syserr")).build()
-            .start();
-
-    // wait for server to start
-    int pid = 0;
-    ServerLauncher pidLauncher = null;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
+  @Override
+  @Test
+  public void stopWithPidDeletesPidFile() throws Exception {
+    givenRunningServer();
 
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
+    assertThatThrownBy(() -> new Builder().setPid(getServerPid()).build().stop())
+        .isInstanceOf(AttachAPINotFoundException.class);
+  }
 
-      // stop with pid only should throw AttachAPINotFoundException
-      try {
-        pidLauncher.stop();
-        fail("FileProcessController should have thrown AttachAPINotFoundException");
-      } catch (AttachAPINotFoundException e) {
-        // passed
-      }
+  /**
+   * Override to assert that STOP with --pid throws AttachAPINotFoundException
+   */
+  @Override
+  @Test
+  public void stopWithPidReturnsStopped() throws Exception {
+    givenRunningServer();
 
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThatThrownBy(() -> new Builder().setPid(getServerPid()).build().stop())
+        .isInstanceOf(AttachAPINotFoundException.class);
+  }
 
-    try {
-      // stop the server
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-      waitForFileToDelete(this.pidFile);
+  /**
+   * Override to assert that STOP with --pid throws AttachAPINotFoundException
+   */
+  @Override
+  @Test
+  public void stopWithPidStopsServerProcess() throws Exception {
+    givenRunningServer();
 
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    } finally {
-      new File(ProcessType.SERVER.getStopRequestFileName()).delete(); // TODO: delete
-    }
+    assertThatThrownBy(() -> new Builder().setPid(getServerPid()).build().stop())
+        .isInstanceOf(AttachAPINotFoundException.class);
   }
 }


[23/23] geode git commit: GEODE-3304: when colocated child bucket is destroyed, it should not impact its parent bucket's creation.

Posted by zh...@apache.org.
GEODE-3304: when colocated child bucket is destroyed, it should not impact its
parent bucket's creation.


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/4deb189d
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/4deb189d
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/4deb189d

Branch: refs/heads/feature/GEODE-3304
Commit: 4deb189d56fcd3d40348cc4ee18c8bb7a91493f4
Parents: 894f3ee
Author: zhouxh <gz...@pivotal.io>
Authored: Wed Aug 9 16:55:41 2017 -0700
Committer: zhouxh <gz...@pivotal.io>
Committed: Fri Aug 11 10:26:04 2017 -0700

----------------------------------------------------------------------
 .../internal/cache/PartitionedRegionDataStore.java      | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/4deb189d/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegionDataStore.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegionDataStore.java b/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegionDataStore.java
index a63a7dd..95e6598 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegionDataStore.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/PartitionedRegionDataStore.java
@@ -2881,8 +2881,16 @@ public class PartitionedRegionDataStore implements HasCachePerfStats {
         }
         if ((isDiskRecovery || pr.isInitialized())
             && (pr.getDataStore().isColocationComplete(bucketId))) {
-          grab = pr.getDataStore().grabFreeBucketRecursively(bucketId, pr, moveSource,
-              forceCreation, replaceOffineData, isRebalance, creationRequestor, isDiskRecovery);
+          try {
+            grab = pr.getDataStore().grabFreeBucketRecursively(bucketId, pr, moveSource,
+                forceCreation, replaceOffineData, isRebalance, creationRequestor, isDiskRecovery);
+          } catch (RegionDestroyedException rde) {
+            if (logger.isDebugEnabled()) {
+              logger.debug("Failed to grab, colocated region for bucketId = {}{}{} is destroyed.",
+                  this.partitionedRegion.getPRId(), PartitionedRegion.BUCKET_ID_SEPARATOR,
+                  bucketId);
+            }
+          }
           if (!grab.nowExists()) {
             if (logger.isDebugEnabled()) {
               logger.debug("Failed grab for bucketId = {}{}{}", this.partitionedRegion.getPRId(),


[09/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePid.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePid.java b/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePid.java
new file mode 100644
index 0000000..d26f73e
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePid.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.internal.process.lang;
+
+import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.geode.internal.util.StopWatch;
+
+/**
+ * Finds unused pids for use in tests.
+ */
+public class AvailablePid {
+
+  static final int LOWER_BOUND = 1;
+  static final int UPPER_BOUND = 64000;
+  static final int DEFAULT_TIMEOUT_MILLIS = 60 * 1000;
+
+  private final Random random;
+  private final int timeoutMillis;
+
+  /**
+   * Construct with no seed and default timeout of 1 minute.
+   */
+  public AvailablePid() {
+    this(new Random(), DEFAULT_TIMEOUT_MILLIS);
+  }
+
+  /**
+   * Construct with specified seed and timeout.
+   */
+  public AvailablePid(final long seed, final int timeoutMillis) {
+    this(new Random(seed), timeoutMillis);
+  }
+
+  /**
+   * Construct with specified Random implementation.
+   */
+  public AvailablePid(final Random random, final int timeoutMillis) {
+    this.random = random;
+    this.timeoutMillis = timeoutMillis;
+  }
+
+  /**
+   * Returns specified pid if it's unused. Else returns randomly unused pid.
+   */
+  public int findAvailablePid(final int pid) throws TimeoutException {
+    if (isProcessAlive(pid)) {
+      return pid;
+    }
+    return findAvailablePid();
+  }
+
+  /**
+   * Returns randomly unused pid.
+   */
+  public int findAvailablePid() throws TimeoutException {
+    StopWatch stopWatch = new StopWatch(true);
+    int pid = random();
+    while (isProcessAlive(pid)) {
+      if (stopWatch.elapsedTimeMillis() > timeoutMillis) {
+        throw new TimeoutException(
+            "Failed to find available pid within " + timeoutMillis + " millis.");
+      }
+      pid = random();
+    }
+    return pid;
+  }
+
+  /**
+   * Returns specified number of randomly unused pids.
+   */
+  public int[] findAvailablePids(final int number) throws TimeoutException {
+    Set<Integer> pids = new HashSet<>();
+    while (pids.size() < number) {
+      int pid = new AvailablePid().findAvailablePid();
+      if (!pids.contains(pid)) {
+        pids.add(pid);
+      }
+    }
+    return Arrays.stream(pids.toArray(new Integer[0])).mapToInt(Integer::intValue).toArray();
+  }
+
+  private int random() {
+    return random.nextInt(UPPER_BOUND - LOWER_BOUND);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePidTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePidTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePidTest.java
new file mode 100644
index 0000000..00beb67
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/lang/AvailablePidTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.internal.process.lang;
+
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
+import static org.apache.geode.internal.process.lang.AvailablePid.DEFAULT_TIMEOUT_MILLIS;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link AvailablePid}.
+ */
+@Category(UnitTest.class)
+public class AvailablePidTest {
+
+  private AvailablePid availablePid;
+
+  @Before
+  public void before() throws Exception {
+    availablePid = new AvailablePid();
+  }
+
+  @Test
+  public void lowerBoundShouldBeLegalPid() throws Exception {
+    assertThat(isProcessAlive(AvailablePid.LOWER_BOUND)).isIn(true, false);
+  }
+
+  @Test
+  public void upperBoundShouldBeLegalPid() throws Exception {
+    assertThat(isProcessAlive(AvailablePid.UPPER_BOUND)).isIn(true, false);
+  }
+
+  @Test(timeout = DEFAULT_TIMEOUT_MILLIS)
+  public void findAvailablePidShouldNotReturnLocalPid() throws Exception {
+    int pid = availablePid.findAvailablePid();
+
+    assertThat(pid).isNotEqualTo(identifyPid());
+  }
+
+  @Test(timeout = DEFAULT_TIMEOUT_MILLIS)
+  public void findAvailablePidShouldNotReturnLivePid() throws Exception {
+    int pid = availablePid.findAvailablePid();
+
+    assertThat(isProcessAlive(pid)).isFalse();
+  }
+
+  @Test(timeout = DEFAULT_TIMEOUT_MILLIS)
+  public void findAvailablePidShouldReturnRandomPid() throws Exception {
+    Random random = spy(new Random());
+    availablePid = new AvailablePid(random, DEFAULT_TIMEOUT_MILLIS);
+
+    availablePid.findAvailablePid();
+
+    verify(random, atLeastOnce()).nextInt(anyInt());
+  }
+
+  @Test(timeout = DEFAULT_TIMEOUT_MILLIS)
+  public void findAvailablePidsShouldReturnSpecifiedNumberOfPids() throws Exception {
+    assertThat(availablePid.findAvailablePids(1)).hasSize(1);
+    assertThat(availablePid.findAvailablePids(2)).hasSize(2);
+    assertThat(availablePid.findAvailablePids(3)).hasSize(3);
+    assertThat(availablePid.findAvailablePids(5)).hasSize(5);
+    assertThat(availablePid.findAvailablePids(8)).hasSize(8);
+  }
+
+  @Test(timeout = DEFAULT_TIMEOUT_MILLIS)
+  public void findAvailablePidsShouldReturnNoDuplicatedPids() throws Exception {
+    assertThatNoPidIsDuplicated(availablePid.findAvailablePids(1));
+    assertThatNoPidIsDuplicated(availablePid.findAvailablePids(2));
+    assertThatNoPidIsDuplicated(availablePid.findAvailablePids(3));
+    assertThatNoPidIsDuplicated(availablePid.findAvailablePids(5));
+    assertThatNoPidIsDuplicated(availablePid.findAvailablePids(8));
+  }
+
+  private void assertThatNoPidIsDuplicated(int[] pids) {
+    Set<Integer> pidSet = Arrays.stream(pids).boxed().collect(Collectors.toSet());
+    assertThat(pidSet).hasSize(pids.length);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/mbean/Process.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/mbean/Process.java b/geode-core/src/test/java/org/apache/geode/internal/process/mbean/Process.java
deleted file mode 100644
index 597da94..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/mbean/Process.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process.mbean;
-
-/**
- * Extracted from LocalProcessControllerDUnitTest.
- * 
- */
-public class Process implements ProcessMBean {
-
-  private final Object object = new Object();
-  private final int pid;
-  private final boolean process;
-  private volatile boolean stop;
-
-  public Process(int pid, boolean process) {
-    this.pid = pid;
-    this.process = process;
-  }
-
-  @Override
-  public int getPid() {
-    return this.pid;
-  }
-
-  public boolean isProcess() {
-    return this.process;
-  }
-
-  @Override
-  public void stop() {
-    synchronized (this.object) {
-      this.stop = true;
-      this.object.notifyAll();
-    }
-  }
-
-  public void waitUntilStopped() throws InterruptedException {
-    synchronized (this.object) {
-      while (!this.stop) {
-        this.object.wait();
-      }
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/mbean/ProcessMBean.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/mbean/ProcessMBean.java b/geode-core/src/test/java/org/apache/geode/internal/process/mbean/ProcessMBean.java
deleted file mode 100644
index 6cebaf3..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/mbean/ProcessMBean.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process.mbean;
-
-/**
- * Extracted from LocalProcessControllerDUnitTest.
- * 
- */
-public interface ProcessMBean {
-  public int getPid();
-
-  public boolean isProcess();
-
-  public void stop();
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerJUnitTest.java
deleted file mode 100644
index 1dc6c0d..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerJUnitTest.java
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process.signal;
-
-import static org.junit.Assert.*;
-
-import java.util.Set;
-
-import org.jmock.Expectations;
-import org.jmock.Mockery;
-import org.jmock.lib.concurrent.Synchroniser;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.internal.util.CollectionUtils;
-import org.apache.geode.test.junit.categories.UnitTest;
-
-/**
- * The AbstractSignalNotificationHandlerJUnitTest class is a test suite of test cases testing the
- * contract and functionality of the AbstractSignalNotificationHandler.
- * </p>
- * 
- * @see org.apache.geode.internal.process.signal.AbstractSignalNotificationHandler
- * @see org.apache.geode.internal.process.signal.Signal
- * @see org.apache.geode.internal.process.signal.SignalEvent
- * @see org.apache.geode.internal.process.signal.SignalListener
- * @see org.jmock.Expectations
- * @see org.jmock.Mockery
- * @see org.junit.Assert
- * @see org.junit.Test
- * @since GemFire 7.0
- */
-@Category(UnitTest.class)
-public class AbstractSignalNotificationHandlerJUnitTest {
-
-  private Mockery mockContext;
-
-  @Before
-  public void setup() {
-    mockContext = new Mockery() {
-      {
-        setImposteriser(ClassImposteriser.INSTANCE);
-        setThreadingPolicy(new Synchroniser());
-      }
-    };
-  }
-
-  @After
-  public void tearDown() {
-    mockContext.assertIsSatisfied();
-    mockContext = null;
-  }
-
-  private AbstractSignalNotificationHandler createSignalNotificationHandler() {
-    return new TestSignalNotificationHandler();
-  }
-
-  @Test
-  public void testAssertNotNullWithNonNullValue() {
-    AbstractSignalNotificationHandler.assertNotNull(new Object(), "TEST");
-  }
-
-  @Test(expected = NullPointerException.class)
-  public void testAssertNotNullWithNullValue() {
-    try {
-      AbstractSignalNotificationHandler.assertNotNull(null, "Expected %1$s message!", "test");
-    } catch (NullPointerException expected) {
-      assertEquals("Expected test message!", expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testAssertStateWithValidState() {
-    AbstractSignalNotificationHandler.assertState(true, "TEST");
-  }
-
-  @Test(expected = IllegalStateException.class)
-  public void testAssertStateWithInvalidState() {
-    try {
-      AbstractSignalNotificationHandler.assertState(false, "Expected %1$s message!", "test");
-    } catch (IllegalStateException expected) {
-      assertEquals("Expected test message!", expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testAssertValidArgumentWithLegalArgument() {
-    AbstractSignalNotificationHandler.assertValidArgument(true, "TEST");
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testAssertValidArgmentWithIllegalArgument() {
-    try {
-      AbstractSignalNotificationHandler.assertValidArgument(false, "Expected %1$s message!",
-          "test");
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Expected test message!", expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testRegisterListener() {
-    final AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
-
-    final SignalListener mockListenerOne = mockContext.mock(SignalListener.class, "SIGALL1");
-    final SignalListener mockListenerTwo = mockContext.mock(SignalListener.class, "SIGALL2");
-
-    assertFalse(signalHandler.isListening(mockListenerOne));
-    assertFalse(signalHandler.isListening(mockListenerTwo));
-
-    for (final Signal signal : Signal.values()) {
-      assertFalse(signalHandler.hasListeners(signal));
-      assertFalse(signalHandler.isListening(mockListenerOne, signal));
-      assertFalse(signalHandler.isListening(mockListenerTwo, signal));
-    }
-
-    assertTrue(signalHandler.registerListener(mockListenerOne));
-    assertTrue(signalHandler.registerListener(mockListenerTwo));
-    assertFalse(signalHandler.registerListener(mockListenerTwo));
-    assertTrue(signalHandler.isListening(mockListenerOne));
-    assertTrue(signalHandler.isListening(mockListenerTwo));
-
-    for (final Signal signal : Signal.values()) {
-      assertTrue(signalHandler.hasListeners(signal));
-      assertTrue(signalHandler.isListening(mockListenerOne, signal));
-      assertTrue(signalHandler.isListening(mockListenerTwo, signal));
-    }
-  }
-
-  @Test(expected = NullPointerException.class)
-  public void testRegisterListenerWithNullSignalListener() {
-    try {
-      createSignalNotificationHandler().registerListener(null);
-    } catch (NullPointerException expected) {
-      assertEquals("The SignalListener to register, listening for all signals cannot be null!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testRegisterListenerWithSignal() {
-    final AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
-
-    final SignalListener mockSigIntListener = mockContext.mock(SignalListener.class, "SIGINT");
-    final SignalListener mockSigIntTermListener =
-        mockContext.mock(SignalListener.class, "SIGINT + SIGTERM");
-
-    assertFalse(signalHandler.isListening(mockSigIntListener));
-    assertFalse(signalHandler.isListening(mockSigIntTermListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertFalse(signalHandler.hasListeners(signal));
-      assertFalse(signalHandler.isListening(mockSigIntListener, signal));
-      assertFalse(signalHandler.isListening(mockSigIntTermListener, signal));
-    }
-
-    assertTrue(signalHandler.registerListener(mockSigIntListener, Signal.SIGINT));
-    assertTrue(signalHandler.registerListener(mockSigIntTermListener, Signal.SIGINT));
-    assertTrue(signalHandler.registerListener(mockSigIntTermListener, Signal.SIGTERM));
-    assertFalse(signalHandler.registerListener(mockSigIntTermListener, Signal.SIGINT));
-    assertTrue(signalHandler.isListening(mockSigIntListener));
-    assertTrue(signalHandler.isListening(mockSigIntTermListener));
-
-    final Set<Signal> expectedSignals = CollectionUtils.asSet(Signal.SIGINT, Signal.SIGTERM);
-
-    for (final Signal signal : Signal.values()) {
-      assertEquals(expectedSignals.contains(signal), signalHandler.hasListeners(signal));
-      switch (signal) {
-        case SIGINT:
-          assertTrue(signalHandler.isListening(mockSigIntListener, signal));
-          assertTrue(signalHandler.isListening(mockSigIntTermListener, signal));
-          break;
-        case SIGTERM:
-          assertFalse(signalHandler.isListening(mockSigIntListener, signal));
-          assertTrue(signalHandler.isListening(mockSigIntTermListener, signal));
-          break;
-        default:
-          assertFalse(signalHandler.isListening(mockSigIntListener, signal));
-          assertFalse(signalHandler.isListening(mockSigIntTermListener, signal));
-      }
-    }
-  }
-
-  @Test(expected = NullPointerException.class)
-  public void testRegisterListenerWithNullSignal() {
-    try {
-      createSignalNotificationHandler()
-          .registerListener(mockContext.mock(SignalListener.class, "SIGALL"), null);
-    } catch (NullPointerException expected) {
-      assertEquals("The signal to register the listener for cannot be null!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = NullPointerException.class)
-  public void testRegisterListenerWithSignalAndNullSignalListener() {
-    try {
-      createSignalNotificationHandler().registerListener(null, Signal.SIGQUIT);
-    } catch (NullPointerException expected) {
-      assertEquals(String.format(
-          "The SignalListener being registered to listen for '%1$s' signals cannot be null!",
-          Signal.SIGQUIT.getName()), expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testUnregisterListener() {
-    final AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
-    final SignalListener mockSignalListener = mockContext.mock(SignalListener.class, "SIGALL");
-
-    assertFalse(signalHandler.isListening(mockSignalListener));
-    assertTrue(signalHandler.registerListener(mockSignalListener));
-    assertTrue(signalHandler.isListening(mockSignalListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertTrue(signalHandler.hasListeners(signal));
-    }
-
-    assertTrue(signalHandler.unregisterListener(mockSignalListener));
-    assertFalse(signalHandler.isListening(mockSignalListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertFalse(signalHandler.hasListeners(signal));
-    }
-
-    assertFalse(signalHandler.unregisterListener(mockSignalListener));
-  }
-
-  @Test
-  public void testUnregisterListenerWithSignalListenerAndAllSignals() {
-    final AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
-    final SignalListener mockSignalListener = mockContext.mock(SignalListener.class, "SIGALL");
-
-    assertFalse(signalHandler.isListening(mockSignalListener));
-    assertTrue(signalHandler.registerListener(mockSignalListener));
-    assertTrue(signalHandler.isListening(mockSignalListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertTrue(signalHandler.hasListeners(signal));
-      assertTrue(signalHandler.isListening(mockSignalListener, signal));
-      assertTrue(signalHandler.unregisterListener(mockSignalListener, signal));
-      assertFalse(signalHandler.isListening(mockSignalListener, signal));
-      assertFalse(signalHandler.hasListeners(signal));
-    }
-
-    assertFalse(signalHandler.unregisterListener(mockSignalListener));
-  }
-
-  @Test
-  public void testUnregisterListenerWithSignalListenerAndSigint() {
-    final AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
-    final SignalListener mockSignalListener = mockContext.mock(SignalListener.class, "SIGALL");
-
-    assertFalse(signalHandler.isListening(mockSignalListener));
-    assertTrue(signalHandler.registerListener(mockSignalListener, Signal.SIGINT));
-    assertTrue(signalHandler.isListening(mockSignalListener));
-    assertTrue(signalHandler.isListening(mockSignalListener, Signal.SIGINT));
-
-    for (final Signal signal : Signal.values()) {
-      if (!Signal.SIGINT.equals(signal)) {
-        assertFalse(signalHandler.hasListeners(signal));
-        assertFalse(signalHandler.isListening(mockSignalListener, signal));
-      }
-    }
-
-    assertTrue(signalHandler.isListening(mockSignalListener));
-    assertTrue(signalHandler.isListening(mockSignalListener, Signal.SIGINT));
-    assertTrue(signalHandler.unregisterListener(mockSignalListener, Signal.SIGINT));
-    assertFalse(signalHandler.isListening(mockSignalListener, Signal.SIGINT));
-    assertFalse(signalHandler.isListening(mockSignalListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertFalse(signalHandler.hasListeners(signal));
-    }
-
-    assertFalse(signalHandler.unregisterListener(mockSignalListener));
-  }
-
-  @Test(expected = NullPointerException.class)
-  public void testUnregisterListenerWithSignalListenerAndNullSignal() {
-    try {
-      createSignalNotificationHandler()
-          .unregisterListener(mockContext.mock(SignalListener.class, "SIGALL"), null);
-    } catch (NullPointerException expected) {
-      assertEquals("The signal from which to unregister the listener cannot be null!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testUnregisterListeners() {
-    final AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
-
-    final SignalListener mockSigQuitListener = mockContext.mock(SignalListener.class, "SIGQUIT");
-    final SignalListener mockSigTermListener = mockContext.mock(SignalListener.class, "SIGTERM");
-    final SignalListener mockSigTermQuitListener =
-        mockContext.mock(SignalListener.class, "SIGTERM + SIGQUIT");
-
-    assertFalse(signalHandler.isListening(mockSigQuitListener));
-    assertFalse(signalHandler.isListening(mockSigTermListener));
-    assertFalse(signalHandler.isListening(mockSigTermQuitListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertFalse(signalHandler.hasListeners(signal));
-    }
-
-    // register sigquit and sigterm listeners...
-    assertTrue(signalHandler.registerListener(mockSigQuitListener, Signal.SIGQUIT));
-    assertTrue(signalHandler.registerListener(mockSigTermListener, Signal.SIGTERM));
-    assertTrue(signalHandler.registerListener(mockSigTermQuitListener, Signal.SIGQUIT));
-    assertTrue(signalHandler.registerListener(mockSigTermQuitListener, Signal.SIGTERM));
-
-    assertTrue(signalHandler.isListening(mockSigQuitListener));
-    assertFalse(signalHandler.isListening(mockSigQuitListener, Signal.SIGINT));
-    assertTrue(signalHandler.isListening(mockSigQuitListener, Signal.SIGQUIT));
-    assertFalse(signalHandler.isListening(mockSigQuitListener, Signal.SIGTERM));
-    assertTrue(signalHandler.isListening(mockSigTermListener));
-    assertFalse(signalHandler.isListening(mockSigTermListener, Signal.SIGINT));
-    assertFalse(signalHandler.isListening(mockSigTermListener, Signal.SIGQUIT));
-    assertTrue(signalHandler.isListening(mockSigTermListener, Signal.SIGTERM));
-    assertTrue(signalHandler.isListening(mockSigTermQuitListener));
-    assertFalse(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGINT));
-    assertTrue(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGQUIT));
-    assertTrue(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGTERM));
-    assertFalse(signalHandler.hasListeners(Signal.SIGINT));
-    assertTrue(signalHandler.hasListeners(Signal.SIGQUIT));
-    assertTrue(signalHandler.hasListeners(Signal.SIGTERM));
-
-    // unregister all sigterm listeners...
-    assertTrue(signalHandler.unregisterListeners(Signal.SIGTERM));
-
-    assertTrue(signalHandler.isListening(mockSigQuitListener));
-    assertFalse(signalHandler.isListening(mockSigQuitListener, Signal.SIGINT));
-    assertTrue(signalHandler.isListening(mockSigQuitListener, Signal.SIGQUIT));
-    assertFalse(signalHandler.isListening(mockSigQuitListener, Signal.SIGTERM));
-    assertFalse(signalHandler.isListening(mockSigTermListener));
-    assertFalse(signalHandler.isListening(mockSigTermListener, Signal.SIGINT));
-    assertFalse(signalHandler.isListening(mockSigTermListener, Signal.SIGQUIT));
-    assertFalse(signalHandler.isListening(mockSigTermListener, Signal.SIGTERM));
-    assertTrue(signalHandler.isListening(mockSigTermQuitListener));
-    assertFalse(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGINT));
-    assertTrue(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGQUIT));
-    assertFalse(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGTERM));
-    assertFalse(signalHandler.hasListeners(Signal.SIGINT));
-    assertTrue(signalHandler.hasListeners(Signal.SIGQUIT));
-    assertFalse(signalHandler.hasListeners(Signal.SIGTERM));
-  }
-
-  @Test(expected = NullPointerException.class)
-  public void testUnregisterListenersWithNullSignal() {
-    try {
-      createSignalNotificationHandler().unregisterListeners(null);
-    } catch (NullPointerException expected) {
-      assertEquals("The signal from which to unregister all listeners cannot be null!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testNotifyListeners() {
-    final AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
-
-    final SignalListener mockSigAllListener = mockContext.mock(SignalListener.class, "SIGALL");
-    final SignalListener mockSigIntListener = mockContext.mock(SignalListener.class, "SIGINT");
-    final SignalListener mockSigQuitListener = mockContext.mock(SignalListener.class, "SIGQUIT");
-    final SignalListener mockSigQuitTermListener =
-        mockContext.mock(SignalListener.class, "SIGQUIT + SIGTERM");
-
-    final SignalEvent sigintEvent = new SignalEvent(this, Signal.SIGINT);
-    final SignalEvent sigioEvent = new SignalEvent(this, Signal.SIGIO);
-    final SignalEvent sigquitEvent = new SignalEvent(this, Signal.SIGQUIT);
-    final SignalEvent sigtermEvent = new SignalEvent(this, Signal.SIGTERM);
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockSigAllListener).handle(with(equal(sigintEvent)));
-        oneOf(mockSigAllListener).handle(with(equal(sigioEvent)));
-        oneOf(mockSigAllListener).handle(with(equal(sigquitEvent)));
-        oneOf(mockSigAllListener).handle(with(equal(sigtermEvent)));
-        oneOf(mockSigIntListener).handle(with(equal(sigintEvent)));
-        oneOf(mockSigQuitListener).handle(with(equal(sigquitEvent)));
-        oneOf(mockSigQuitTermListener).handle(with(equal(sigquitEvent)));
-        oneOf(mockSigQuitTermListener).handle(with(equal(sigtermEvent)));
-      }
-    });
-
-    assertFalse(signalHandler.isListening(mockSigAllListener));
-    assertFalse(signalHandler.isListening(mockSigIntListener));
-    assertFalse(signalHandler.isListening(mockSigQuitListener));
-    assertFalse(signalHandler.isListening(mockSigQuitTermListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertFalse(signalHandler.hasListeners(signal));
-    }
-
-    assertTrue(signalHandler.registerListener(mockSigAllListener));
-    assertTrue(signalHandler.registerListener(mockSigIntListener, Signal.SIGINT));
-    assertTrue(signalHandler.registerListener(mockSigQuitListener, Signal.SIGQUIT));
-    assertTrue(signalHandler.registerListener(mockSigQuitTermListener, Signal.SIGQUIT));
-    assertTrue(signalHandler.registerListener(mockSigQuitTermListener, Signal.SIGTERM));
-    assertTrue(signalHandler.isListening(mockSigAllListener));
-    assertTrue(signalHandler.isListening(mockSigIntListener));
-    assertTrue(signalHandler.isListening(mockSigQuitListener));
-    assertTrue(signalHandler.isListening(mockSigQuitTermListener));
-
-    for (final Signal signal : Signal.values()) {
-      assertTrue(signalHandler.hasListeners(signal));
-      assertTrue(signalHandler.isListening(mockSigAllListener, signal));
-
-      switch (signal) {
-        case SIGINT:
-          assertTrue(signalHandler.isListening(mockSigIntListener, signal));
-          assertFalse(signalHandler.isListening(mockSigQuitListener, signal));
-          assertFalse(signalHandler.isListening(mockSigQuitTermListener, signal));
-          break;
-        case SIGQUIT:
-          assertFalse(signalHandler.isListening(mockSigIntListener, signal));
-          assertTrue(signalHandler.isListening(mockSigQuitListener, signal));
-          assertTrue(signalHandler.isListening(mockSigQuitTermListener, signal));
-          break;
-        case SIGTERM:
-          assertFalse(signalHandler.isListening(mockSigIntListener, signal));
-          assertFalse(signalHandler.isListening(mockSigQuitListener, signal));
-          assertTrue(signalHandler.isListening(mockSigQuitTermListener, signal));
-          break;
-        default:
-          assertFalse(signalHandler.isListening(mockSigIntListener, signal));
-          assertFalse(signalHandler.isListening(mockSigQuitListener, signal));
-          assertFalse(signalHandler.isListening(mockSigQuitTermListener, signal));
-      }
-    }
-
-    signalHandler.notifyListeners(sigintEvent);
-    signalHandler.notifyListeners(sigioEvent);
-    signalHandler.notifyListeners(sigquitEvent);
-    signalHandler.notifyListeners(sigtermEvent);
-
-    // notification verification handled by mockContext.assertIsSatisfied in tearDown()
-  }
-
-  private static class TestSignalNotificationHandler extends AbstractSignalNotificationHandler {
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerTest.java
new file mode 100644
index 0000000..d1f422d
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandlerTest.java
@@ -0,0 +1,406 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process.signal;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.Set;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.util.CollectionUtils;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link AbstractSignalNotificationHandler}.
+ *
+ * @since GemFire 7.0
+ */
+@Category(UnitTest.class)
+public class AbstractSignalNotificationHandlerTest {
+
+  @Test
+  public void assertNotNullWithNonNullValueDoesNotThrow() {
+    AbstractSignalNotificationHandler.assertNotNull(new Object(), "TEST");
+  }
+
+  @Test
+  public void assertNotNullWithNullValueThrowsNullPointerException() {
+    assertThatThrownBy(() -> AbstractSignalNotificationHandler.assertNotNull(null,
+        "Expected %1$s message!", "test")).isInstanceOf(NullPointerException.class);
+  }
+
+  @Test
+  public void assertStateWithValidStateDoesNotThrow() {
+    AbstractSignalNotificationHandler.assertState(true, "TEST");
+  }
+
+  @Test
+  public void assertStateWithInvalidStateThrowsIllegalStateException() {
+    assertThatThrownBy(() -> AbstractSignalNotificationHandler.assertState(false,
+        "Expected %1$s message!", "test")).isInstanceOf(IllegalStateException.class);
+  }
+
+  @Test
+  public void assertValidArgumentWithLegalArgumentDoesNotThrow() {
+    AbstractSignalNotificationHandler.assertValidArgument(true, "TEST");
+  }
+
+  @Test
+  public void assertValidArgumentWithIllegalArgumentThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> AbstractSignalNotificationHandler.assertValidArgument(false,
+        "Expected %1$s message!", "test")).isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void registerListener() {
+    AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
+
+    SignalListener mockListenerOne = mock(SignalListener.class, "SIGALL1");
+    SignalListener mockListenerTwo = mock(SignalListener.class, "SIGALL2");
+
+    assertThat(signalHandler.isListening(mockListenerOne)).isFalse();
+    assertThat(signalHandler.isListening(mockListenerTwo)).isFalse();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isFalse();
+      assertThat(signalHandler.isListening(mockListenerOne, signal)).isFalse();
+      assertThat(signalHandler.isListening(mockListenerTwo, signal)).isFalse();
+    }
+
+    assertThat(signalHandler.registerListener(mockListenerOne)).isTrue();
+    assertThat(signalHandler.registerListener(mockListenerTwo)).isTrue();
+    assertThat(signalHandler.registerListener(mockListenerTwo)).isFalse();
+    assertThat(signalHandler.isListening(mockListenerOne)).isTrue();
+    assertThat(signalHandler.isListening(mockListenerTwo)).isTrue();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isTrue();
+      assertThat(signalHandler.isListening(mockListenerOne, signal)).isTrue();
+      assertThat(signalHandler.isListening(mockListenerTwo, signal)).isTrue();
+    }
+  }
+
+  @Test
+  public void registerListenerWithNullSignalListenerThrowsNullPointerException() {
+    assertThatThrownBy(() -> createSignalNotificationHandler().registerListener(null))
+        .isInstanceOf(NullPointerException.class)
+        .hasMessage("The SignalListener to register, listening for all signals cannot be null!");
+  }
+
+  @Test
+  public void registerListenerWithSignal() {
+    AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
+
+    SignalListener mockSigIntListener = mock(SignalListener.class, "SIGINT");
+    SignalListener mockSigIntTermListener = mock(SignalListener.class, "SIGINT + SIGTERM");
+
+    assertThat(signalHandler.isListening(mockSigIntListener)).isFalse();
+    assertThat(signalHandler.isListening(mockSigIntTermListener)).isFalse();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isFalse();
+      assertThat(signalHandler.isListening(mockSigIntListener, signal)).isFalse();
+      assertThat(signalHandler.isListening(mockSigIntTermListener, signal)).isFalse();
+    }
+
+    assertThat(signalHandler.registerListener(mockSigIntListener, Signal.SIGINT)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigIntTermListener, Signal.SIGINT)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigIntTermListener, Signal.SIGTERM)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigIntTermListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigIntListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigIntTermListener)).isTrue();
+
+    Set<Signal> expectedSignals = CollectionUtils.asSet(Signal.SIGINT, Signal.SIGTERM);
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isEqualTo(expectedSignals.contains(signal));
+      switch (signal) {
+        case SIGINT:
+          assertThat(signalHandler.isListening(mockSigIntListener, signal)).isTrue();
+          assertThat(signalHandler.isListening(mockSigIntTermListener, signal)).isTrue();
+          break;
+        case SIGTERM:
+          assertThat(signalHandler.isListening(mockSigIntListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigIntTermListener, signal)).isTrue();
+          break;
+        default:
+          assertThat(signalHandler.isListening(mockSigIntListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigIntTermListener, signal)).isFalse();
+      }
+    }
+  }
+
+  @Test
+  public void registerListenerWithNullSignalThrowsNullPointerException() {
+    assertThatThrownBy(() -> createSignalNotificationHandler()
+        .registerListener(mock(SignalListener.class, "SIGALL"), null))
+            .isInstanceOf(NullPointerException.class)
+            .hasMessage("The signal to register the listener for cannot be null!");
+  }
+
+  @Test
+  public void registerListenerWithSignalAndNullSignalListenerThrowsNullPointerException() {
+    assertThatThrownBy(
+        () -> createSignalNotificationHandler().registerListener(null, Signal.SIGQUIT))
+            .isInstanceOf(NullPointerException.class)
+            .hasMessage(signalListenerForSignalCannotBeNullErrorMessage(Signal.SIGQUIT));
+  }
+
+  @Test
+  public void unregisterListener() {
+    AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
+    SignalListener mockSignalListener = mock(SignalListener.class, "SIGALL");
+
+    assertThat(signalHandler.isListening(mockSignalListener)).isFalse();
+    assertThat(signalHandler.registerListener(mockSignalListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSignalListener)).isTrue();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isTrue();
+    }
+
+    assertThat(signalHandler.unregisterListener(mockSignalListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSignalListener)).isFalse();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isFalse();
+    }
+
+    assertThat(signalHandler.unregisterListener(mockSignalListener)).isFalse();
+  }
+
+  @Test
+  public void unregisterListenerWithSignalListenerAndAllSignals() {
+    AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
+    SignalListener mockSignalListener = mock(SignalListener.class, "SIGALL");
+
+    assertThat(signalHandler.isListening(mockSignalListener)).isFalse();
+    assertThat(signalHandler.registerListener(mockSignalListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSignalListener)).isTrue();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isTrue();
+      assertThat(signalHandler.isListening(mockSignalListener, signal)).isTrue();
+      assertThat(signalHandler.unregisterListener(mockSignalListener, signal)).isTrue();
+      assertThat(signalHandler.isListening(mockSignalListener, signal)).isFalse();
+      assertThat(signalHandler.hasListeners(signal)).isFalse();
+    }
+
+    assertThat(signalHandler.unregisterListener(mockSignalListener)).isFalse();
+  }
+
+  @Test
+  public void unregisterListenerWithSignalListenerAndSigint() {
+    AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
+    SignalListener mockSignalListener = mock(SignalListener.class, "SIGALL");
+
+    assertThat(signalHandler.isListening(mockSignalListener)).isFalse();
+    assertThat(signalHandler.registerListener(mockSignalListener, Signal.SIGINT)).isTrue();
+    assertThat(signalHandler.isListening(mockSignalListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSignalListener, Signal.SIGINT)).isTrue();
+
+    for (Signal signal : Signal.values()) {
+      if (!Signal.SIGINT.equals(signal)) {
+        assertThat(signalHandler.hasListeners(signal)).isFalse();
+        assertThat(signalHandler.isListening(mockSignalListener, signal)).isFalse();
+      }
+    }
+
+    assertThat(signalHandler.isListening(mockSignalListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSignalListener, Signal.SIGINT)).isTrue();
+    assertThat(signalHandler.unregisterListener(mockSignalListener, Signal.SIGINT)).isTrue();
+    assertThat(signalHandler.isListening(mockSignalListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSignalListener)).isFalse();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isFalse();
+    }
+
+    assertThat(signalHandler.unregisterListener(mockSignalListener)).isFalse();
+  }
+
+  @Test
+  public void unregisterListenerWithSignalListenerAndNullSignalThrowsNullPointerException() {
+    assertThatThrownBy(() -> createSignalNotificationHandler()
+        .unregisterListener(mock(SignalListener.class, "SIGALL"), null))
+            .isInstanceOf(NullPointerException.class)
+            .hasMessage("The signal from which to unregister the listener cannot be null!");
+  }
+
+  @Test
+  public void unregisterListeners() {
+    AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
+
+    SignalListener mockSigQuitListener = mock(SignalListener.class, "SIGQUIT");
+    SignalListener mockSigTermListener = mock(SignalListener.class, "SIGTERM");
+    SignalListener mockSigTermQuitListener = mock(SignalListener.class, "SIGTERM + SIGQUIT");
+
+    assertThat(signalHandler.isListening(mockSigQuitListener)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener)).isFalse();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isFalse();
+    }
+
+    // register sigquit and sigterm listeners...
+    assertThat(signalHandler.registerListener(mockSigQuitListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigTermListener, Signal.SIGTERM)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigTermQuitListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigTermQuitListener, Signal.SIGTERM)).isTrue();
+
+    assertThat(signalHandler.isListening(mockSigQuitListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigQuitListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigQuitListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.isListening(mockSigQuitListener, Signal.SIGTERM)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigTermListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener, Signal.SIGQUIT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener, Signal.SIGTERM)).isTrue();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGTERM)).isTrue();
+    assertThat(signalHandler.hasListeners(Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.hasListeners(Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.hasListeners(Signal.SIGTERM)).isTrue();
+
+    // unregister all sigterm listeners...
+    assertThat(signalHandler.unregisterListeners(Signal.SIGTERM)).isTrue();
+
+    assertThat(signalHandler.isListening(mockSigQuitListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigQuitListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigQuitListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.isListening(mockSigQuitListener, Signal.SIGTERM)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener, Signal.SIGQUIT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermListener, Signal.SIGTERM)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.isListening(mockSigTermQuitListener, Signal.SIGTERM)).isFalse();
+    assertThat(signalHandler.hasListeners(Signal.SIGINT)).isFalse();
+    assertThat(signalHandler.hasListeners(Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.hasListeners(Signal.SIGTERM)).isFalse();
+  }
+
+  @Test
+  public void unregisterListenersWithNullSignalThrowsNullPointerException() {
+    assertThatThrownBy(() -> createSignalNotificationHandler().unregisterListeners(null))
+        .isInstanceOf(NullPointerException.class)
+        .hasMessage("The signal from which to unregister all listeners cannot be null!");
+  }
+
+  @Test
+  public void notifyListeners() {
+    AbstractSignalNotificationHandler signalHandler = createSignalNotificationHandler();
+
+    SignalListener mockSigAllListener = mock(SignalListener.class, "SIGALL");
+    SignalListener mockSigIntListener = mock(SignalListener.class, "SIGINT");
+    SignalListener mockSigQuitListener = mock(SignalListener.class, "SIGQUIT");
+    SignalListener mockSigQuitTermListener = mock(SignalListener.class, "SIGQUIT + SIGTERM");
+
+    SignalEvent sigintEvent = new SignalEvent(this, Signal.SIGINT);
+    SignalEvent sigioEvent = new SignalEvent(this, Signal.SIGIO);
+    SignalEvent sigquitEvent = new SignalEvent(this, Signal.SIGQUIT);
+    SignalEvent sigtermEvent = new SignalEvent(this, Signal.SIGTERM);
+
+    assertThat(signalHandler.isListening(mockSigAllListener)).isFalse();
+    assertThat(signalHandler.isListening(mockSigIntListener)).isFalse();
+    assertThat(signalHandler.isListening(mockSigQuitListener)).isFalse();
+    assertThat(signalHandler.isListening(mockSigQuitTermListener)).isFalse();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isFalse();
+    }
+
+    assertThat(signalHandler.registerListener(mockSigAllListener)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigIntListener, Signal.SIGINT)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigQuitListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigQuitTermListener, Signal.SIGQUIT)).isTrue();
+    assertThat(signalHandler.registerListener(mockSigQuitTermListener, Signal.SIGTERM)).isTrue();
+    assertThat(signalHandler.isListening(mockSigAllListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigIntListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigQuitListener)).isTrue();
+    assertThat(signalHandler.isListening(mockSigQuitTermListener)).isTrue();
+
+    for (Signal signal : Signal.values()) {
+      assertThat(signalHandler.hasListeners(signal)).isTrue();
+      assertThat(signalHandler.isListening(mockSigAllListener, signal)).isTrue();
+
+      switch (signal) {
+        case SIGINT:
+          assertThat(signalHandler.isListening(mockSigIntListener, signal)).isTrue();
+          assertThat(signalHandler.isListening(mockSigQuitListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigQuitTermListener, signal)).isFalse();
+          break;
+        case SIGQUIT:
+          assertThat(signalHandler.isListening(mockSigIntListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigQuitListener, signal)).isTrue();
+          assertThat(signalHandler.isListening(mockSigQuitTermListener, signal)).isTrue();
+          break;
+        case SIGTERM:
+          assertThat(signalHandler.isListening(mockSigIntListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigQuitListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigQuitTermListener, signal)).isTrue();
+          break;
+        default:
+          assertThat(signalHandler.isListening(mockSigIntListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigQuitListener, signal)).isFalse();
+          assertThat(signalHandler.isListening(mockSigQuitTermListener, signal)).isFalse();
+      }
+    }
+
+    signalHandler.notifyListeners(sigintEvent);
+    signalHandler.notifyListeners(sigioEvent);
+    signalHandler.notifyListeners(sigquitEvent);
+    signalHandler.notifyListeners(sigtermEvent);
+
+    verify(mockSigAllListener, times(1)).handle(eq(sigintEvent));
+    verify(mockSigAllListener, times(1)).handle(eq(sigioEvent));
+    verify(mockSigAllListener, times(1)).handle(eq(sigquitEvent));
+    verify(mockSigAllListener, times(1)).handle(eq(sigtermEvent));
+
+    verify(mockSigIntListener, times(1)).handle(eq(sigintEvent));
+
+    verify(mockSigQuitListener, times(1)).handle(eq(sigquitEvent));
+
+    verify(mockSigQuitTermListener, times(1)).handle(eq(sigquitEvent));
+    verify(mockSigQuitTermListener, times(1)).handle(eq(sigtermEvent));
+  }
+
+  private String signalListenerForSignalCannotBeNullErrorMessage(Signal signal) {
+    return String.format(
+        "The SignalListener being registered to listen for '%1$s' signals cannot be null!",
+        signal.getName());
+  }
+
+  private AbstractSignalNotificationHandler createSignalNotificationHandler() {
+    return new TestSignalNotificationHandler();
+  }
+
+  private static class TestSignalNotificationHandler extends AbstractSignalNotificationHandler {
+    // nothing here
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/resources/META-INF/services/org.apache.geode.distributed.ServerLauncherCacheProvider
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/META-INF/services/org.apache.geode.distributed.ServerLauncherCacheProvider b/geode-core/src/test/resources/META-INF/services/org.apache.geode.distributed.ServerLauncherCacheProvider
index 5dc9077..b87b276 100644
--- a/geode-core/src/test/resources/META-INF/services/org.apache.geode.distributed.ServerLauncherCacheProvider
+++ b/geode-core/src/test/resources/META-INF/services/org.apache.geode.distributed.ServerLauncherCacheProvider
@@ -1 +1 @@
-org.apache.geode.distributed.MockServerLauncherCacheProvider
\ No newline at end of file
+org.apache.geode.distributed.TestServerLauncherCacheProvider
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
----------------------------------------------------------------------
diff --git a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
index 743a8c2..9044109 100755
--- a/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
+++ b/geode-core/src/test/resources/org/apache/geode/codeAnalysis/sanctionedSerializables.txt
@@ -201,6 +201,7 @@ org/apache/geode/cache/util/Gateway$OrderPolicy,false
 org/apache/geode/cache/wan/GatewaySender$OrderPolicy,false
 org/apache/geode/compression/CompressionException,true,4118639654597191235
 org/apache/geode/compression/SnappyCompressor,true,496609875302446099
+org/apache/geode/config/internal/ClusterConfigurationNotAvailableException,true,771319836094239284
 org/apache/geode/distributed/AbstractLauncher$Status,false,description:java/lang/String
 org/apache/geode/distributed/DistributedSystemDisconnectedException,true,-2484849299224086250
 org/apache/geode/distributed/FutureCancelledException,true,-4599338440381989844
@@ -249,7 +250,6 @@ org/apache/geode/internal/SystemAdmin$CombinedResources,false
 org/apache/geode/internal/admin/CompoundEntrySnapshot,true,5776382582897895718,allUserAttributes:java/util/Set,allValues:java/util/Set,hitRatio:float,hitRatioSum:double,hitResponders:long,lastAccessTime:long,lastModifiedTime:long,name:java/lang/Object,numHits:long,numMisses:long
 org/apache/geode/internal/admin/CompoundRegionSnapshot,true,6295026394298398004,allCacheLoaders:java/util/Set,allCacheWriters:java/util/Set,allCapControllers:java/util/Set,allConcLevels:java/util/Set,allCustomIdle:java/util/HashSet,allCustomTtl:java/util/HashSet,allDataPolicies:java/util/Set,allEntryIdleTimeout:java/util/Set,allEntryTtl:java/util/Set,allInitialCaps:java/util/Set,allKeyConstraints:java/util/Set,allListeners:java/util/Set,allLoadFactors:java/util/Set,allRegionIdleTimeout:java/util/Set,allRegionTtl:java/util/Set,allScopes:java/util/Set,allStatsEnabled:java/util/Set,allUserAttributes:java/util/Set,allValueConstraints:java/util/Set,hitRatio:float,hitRatioSum:double,hitResponders:long,lastAccessTime:long,lastModifiedTime:long,name:java/lang/String,numHits:long,numMisses:long
 org/apache/geode/internal/admin/StatAlert,true,5725457607122449170,definitionId:int,time:java/util/Date,values:java/lang/Number[]
-org/apache/geode/internal/admin/remote/DistributionLocatorId,true,6587390186971937865,bindAddress:java/lang/String,host:java/net/InetAddress,hostnameForClients:java/lang/String,peerLocator:boolean,port:int,serverLocator:boolean
 org/apache/geode/internal/admin/remote/EntryValueNodeImpl,false,fields:org/apache/geode/internal/admin/remote/EntryValueNodeImpl[],name:java/lang/String,primitive:boolean,primitiveVal:java/lang/Object,type:java/lang/String
 org/apache/geode/internal/cache/BucketAdvisor$SetFromMap,true,2454657854757543876,m:java/util/Map
 org/apache/geode/internal/cache/BucketNotFoundException,true,2898657229184289911
@@ -358,6 +358,7 @@ org/apache/geode/internal/concurrent/CompactConcurrentHashSet2,true,724906924676
 org/apache/geode/internal/concurrent/CompactConcurrentHashSet2$Segment,true,2249069246763182397,loadFactor:float
 org/apache/geode/internal/concurrent/ConcurrentHashSet,true,-3338819662572203596,map:java/util/concurrent/ConcurrentHashMap
 org/apache/geode/internal/concurrent/LI,true,-6014738350371493969,className:java/lang/String,identityHashCode:int,lockedStackFrame:java/lang/StackTraceElement
+org/apache/geode/internal/config/ClusterConfigurationNotAvailableException,true,771319836094239284
 org/apache/geode/internal/datasource/AbstractDataSource,false,configProps:org/apache/geode/internal/datasource/ConfiguredDataSourceProperties,isActive:boolean,jdbcDriver:java/lang/String,loginTimeOut:int,password:java/lang/String,serverName:java/lang/String,url:java/lang/String,user:java/lang/String
 org/apache/geode/internal/datasource/AbstractPoolCache,false,INIT_LIMIT:int,MAX_LIMIT:int,activeConnections:int,configProps:org/apache/geode/internal/datasource/ConfiguredDataSourceProperties,connEventListner:java/util/EventListener,expirationTime:int,expiredConns:java/util/List,loginTimeOut:int,sleepTime:long,th:java/lang/Thread,timeOut:int,totalConnections:int
 org/apache/geode/internal/datasource/ConfiguredDataSourceProperties,true,1241739895646314739,connPoolDSClass:java/lang/String,expirationTime:int,initialPoolSize:int,jdbcDriver:java/lang/String,loginTimeOut:int,maxPoolSize:int,mcfClass:java/lang/String,password:java/lang/String,timeOut:int,txnType:java/lang/String,url:java/lang/String,user:java/lang/String,xadsClass:java/lang/String
@@ -540,9 +541,6 @@ org/apache/geode/management/internal/cli/functions/CreateDefinedIndexesFunction,
 org/apache/geode/management/internal/cli/functions/CreateDiskStoreFunction,true,1
 org/apache/geode/management/internal/cli/functions/CreateIndexFunction,true,1
 org/apache/geode/management/internal/cli/functions/DataCommandFunction,true,1,optimizeForWrite:boolean
-org/apache/geode/management/internal/cli/functions/DataCommandFunction$SelectExecStep,true,1
-org/apache/geode/management/internal/cli/functions/DataCommandFunction$SelectMoveStep,true,1
-org/apache/geode/management/internal/cli/functions/DataCommandFunction$SelectQuitStep,true,1
 org/apache/geode/management/internal/cli/functions/DeployFunction,true,1
 org/apache/geode/management/internal/cli/functions/DescribeDiskStoreFunction,false
 org/apache/geode/management/internal/cli/functions/DestroyDiskStoreFunction,true,1
@@ -594,9 +592,6 @@ org/apache/geode/management/internal/cli/functions/UndeployFunction,true,1
 org/apache/geode/management/internal/cli/functions/UnregisterFunction,true,1
 org/apache/geode/management/internal/cli/functions/UserFunctionExecution,true,1
 org/apache/geode/management/internal/cli/json/GfJsonException,true,36449998984143318
-org/apache/geode/management/internal/cli/multistep/CLIMultiStepHelper$RemoteStep,false,commandArguments:java/lang/Object[],name:java/lang/String
-org/apache/geode/management/internal/cli/multistep/CLIMultiStepHelper$StepExecutionException,true,1,message:java/lang/String
-org/apache/geode/management/internal/cli/multistep/CLIStepExecption,false,result:org/apache/geode/management/cli/Result
 org/apache/geode/management/internal/cli/result/CommandResultException,true,1,result:org/apache/geode/management/cli/Result
 org/apache/geode/management/internal/cli/result/ResultDataException,true,3851919811942980944
 org/apache/geode/management/internal/cli/result/TableBuilder$Align,false


[17/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTest.java
index b856361..a5c20f4 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTest.java
@@ -17,14 +17,21 @@ package org.apache.geode.distributed;
 import static com.googlecode.catchexception.apis.BDDCatchException.caughtException;
 import static com.googlecode.catchexception.apis.BDDCatchException.when;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.apache.geode.distributed.DistributedSystem.PROPERTIES_FILE_PROPERTY;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPort;
+import static org.apache.geode.internal.DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY;
 import static org.assertj.core.api.BDDAssertions.assertThat;
 import static org.assertj.core.api.BDDAssertions.then;
 
-import org.apache.geode.distributed.LocatorLauncher.Builder;
-import org.apache.geode.distributed.LocatorLauncher.Command;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.i18n.LocalizedStrings;
-import org.apache.geode.test.junit.categories.IntegrationTest;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.InetAddress;
+import java.util.Properties;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.contrib.java.lang.system.RestoreSystemProperties;
@@ -32,19 +39,19 @@ import org.junit.experimental.categories.Category;
 import org.junit.rules.TemporaryFolder;
 import org.junit.rules.TestName;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.util.Properties;
+import org.apache.geode.distributed.LocatorLauncher.Builder;
+import org.apache.geode.distributed.LocatorLauncher.Command;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
- * Integration tests for LocatorLauncher. These tests require file system I/O.
+ * Integration tests for using {@link LocatorLauncher} as an in-process API within an existing JVM.
  */
 @Category(IntegrationTest.class)
 public class LocatorLauncherIntegrationTest {
 
+  private static final String CURRENT_DIRECTORY = System.getProperty("user.dir");
+
   @Rule
   public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
 
@@ -55,177 +62,242 @@ public class LocatorLauncherIntegrationTest {
   public final TestName testName = new TestName();
 
   @Test
-  public void testBuilderParseArgumentsWithValuesSeparatedWithCommas() throws Exception {
-    // given: a new builder and working directory
-    String expectedWorkingDirectory = this.temporaryFolder.getRoot().getCanonicalPath();
+  public void buildWithMemberNameSetInGemFireProperties() throws Exception {
+    // given: gemfire.properties with a name
+    givenGemFirePropertiesFile(withMemberName());
+
+    // when: starting with null MemberName
+    LocatorLauncher launcher = new Builder().setCommand(Command.START).build();
+
+    // then: name in gemfire.properties file should be used for MemberName
+    assertThat(launcher.getMemberName()).isNull(); // name will be read during start()
+  }
+
+  @Test
+  public void buildWithNoMemberNameThrowsIllegalStateException() throws Exception {
+    // given: gemfire.properties with no name
+    givenGemFirePropertiesFile(withoutMemberName());
+
+    // when: no MemberName is specified
+    when(new Builder().setCommand(Command.START)).build();
+
+    // then: throw IllegalStateException
+    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class)
+        .hasMessage(memberNameValidationErrorMessage());
+  }
+
+  @Test
+  public void buildWithWorkingDirectoryNotEqualToCurrentDirectoryThrowsIllegalStateException()
+      throws Exception {
+    // given: using LocatorLauncher in-process
+
+    // when: setting WorkingDirectory to non-current directory
+    when(new Builder().setCommand(Command.START).setMemberName("memberOne")
+        .setWorkingDirectory(getWorkingDirectoryPath())).build();
+
+    // then: throw IllegalStateException
+    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class)
+        .hasMessage(workingDirectoryOptionNotValidErrorMessage());
+  }
+
+  @Test
+  public void parseArgumentsParsesValuesSeparatedByCommas() throws Exception {
+    // given: a new builder
     Builder builder = new Builder();
 
     // when: parsing many arguments
     builder.parseArguments("start", "memberOne", "--bind-address",
-        InetAddress.getLocalHost().getHostAddress(), "--dir", expectedWorkingDirectory,
+        InetAddress.getLocalHost().getHostAddress(), "--dir", getWorkingDirectoryPath(),
         "--hostname-for-clients", "Tucows", "--pid", "1234", "--port", "11235", "--redirect-output",
         "--force", "--debug");
 
     // then: the getters should return properly parsed values
     assertThat(builder.getCommand()).isEqualTo(Command.START);
     assertThat(builder.getBindAddress()).isEqualTo(InetAddress.getLocalHost());
-    assertThat(builder.getWorkingDirectory()).isEqualTo(expectedWorkingDirectory);
+    assertThat(builder.getDebug()).isTrue();
+    assertThat(builder.getForce()).isTrue();
     assertThat(builder.getHostnameForClients()).isEqualTo("Tucows");
     assertThat(builder.getPid().intValue()).isEqualTo(1234);
     assertThat(builder.getPort().intValue()).isEqualTo(11235);
     assertThat(builder.getRedirectOutput()).isTrue();
-    assertThat(builder.getForce()).isTrue();
-    assertThat(builder.getDebug()).isTrue();
+    assertThat(builder.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
   @Test
-  public void testBuilderParseArgumentsWithValuesSeparatedWithEquals() throws Exception {
-    // given: a new builder and a directory
-    String expectedWorkingDirectory = this.temporaryFolder.getRoot().getCanonicalPath();
+  public void parseArgumentsParsesValuesSeparatedByEquals() throws Exception {
+    // given: a new builder
     Builder builder = new Builder();
 
     // when: parsing arguments with values separated by equals
-    builder.parseArguments("start", "--dir=" + expectedWorkingDirectory, "--port=" + "12345",
+    builder.parseArguments("start", "--dir=" + getWorkingDirectoryPath(), "--port=" + "12345",
         "memberOne");
 
     // then: the getters should return properly parsed values
+    assertThat(builder.getBindAddress()).isNull();
     assertThat(builder.getCommand()).isEqualTo(Command.START);
     assertThat(builder.getDebug()).isFalse();
     assertThat(builder.getForce()).isFalse();
     assertThat(builder.getHelp()).isFalse();
-    assertThat(builder.getBindAddress()).isNull();
     assertThat(builder.getHostnameForClients()).isNull();
     assertThat(builder.getMemberName()).isEqualTo("memberOne");
     assertThat(builder.getPid()).isNull();
-    assertThat(builder.getWorkingDirectory()).isEqualTo(expectedWorkingDirectory);
     assertThat(builder.getPort().intValue()).isEqualTo(12345);
+    assertThat(builder.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
   @Test
-  public void testBuildWithMemberNameSetInGemFirePropertiesOnStart() throws Exception {
-    // given: gemfire.properties with a name
-    Properties gemfireProperties = new Properties();
-    gemfireProperties.setProperty(NAME, "locator123");
-    useGemFirePropertiesFileInTemporaryFolder(DistributionConfig.GEMFIRE_PREFIX + "properties",
-        gemfireProperties);
+  public void getWorkingDirectoryReturnsCurrentDirectoryByDefault() throws Exception {
+    // given:
 
-    // when: starting with null MemberName
-    LocatorLauncher launcher = new Builder().setCommand(Command.START).build();
+    // when: not setting WorkingDirectory
 
-    // then: name in gemfire.properties file should be used for MemberName
-    assertThat(launcher).isNotNull();
-    assertThat(launcher.getCommand()).isEqualTo(Command.START);
-    assertThat(launcher.getMemberName()).isNull();
+    // then: getDirectory returns default
+    assertThat(new Builder().getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
   }
 
   @Test
-  public void testBuildWithNoMemberNameOnStart() throws Exception {
-    // given: gemfire.properties with no name
-    useGemFirePropertiesFileInTemporaryFolder(DistributionConfig.GEMFIRE_PREFIX + "properties",
-        new Properties());
+  public void setWorkingDirectoryToNullUsesCurrentDirectory() throws Exception {
+    // given: a new builder
+    Builder builder = new Builder();
 
-    // when: no MemberName is specified
-    when(new Builder().setCommand(Command.START)).build();
+    // when: setting WorkingDirectory to null
+    assertThat(builder.setWorkingDirectory(null)).isSameAs(builder);
 
-    // then: throw IllegalStateException
-    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class)
-        .hasMessage(LocalizedStrings.Launcher_Builder_MEMBER_NAME_VALIDATION_ERROR_MESSAGE
-            .toLocalizedString("Locator"));
+    // then: getDirectory returns default
+    assertThat(builder.getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
   }
 
   @Test
-  public void testBuilderSetAndGetWorkingDirectory() throws Exception {
-    // given: a new builder and a directory
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
+  public void setWorkingDirectoryToEmptyStringUsesCurrentDirectory() throws Exception {
+    // given: a new builder
     Builder builder = new Builder();
 
-    // when: not setting WorkingDirectory
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
-
-    // when: setting WorkingDirectory to null
-    assertThat(builder.setWorkingDirectory(null)).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
-
     // when: setting WorkingDirectory to empty string
     assertThat(builder.setWorkingDirectory("")).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
+
+    // then: getDirectory returns default
+    assertThat(builder.getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
+  }
+
+  @Test
+  public void setWorkingDirectoryToBlankStringUsesCurrentDirectory() throws Exception {
+    // given: a new builder
+    Builder builder = new Builder();
 
     // when: setting WorkingDirectory to white space
     assertThat(builder.setWorkingDirectory("  ")).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
+
+    // then: getDirectory returns default
+    assertThat(builder.getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
+  }
+
+  @Test
+  public void setWorkingDirectoryToExistingDirectory() throws Exception {
+    // given: a new builder
+    Builder builder = new Builder();
 
     // when: setting WorkingDirectory to a directory
-    assertThat(builder.setWorkingDirectory(rootFolder)).isSameAs(builder);
-    // then: getWorkingDirectory returns that directory
-    assertThat(builder.getWorkingDirectory()).isEqualTo(rootFolder);
+    assertThat(builder.setWorkingDirectory(getWorkingDirectoryPath())).isSameAs(builder);
 
-    // when: setting WorkingDirectory to null (again)
-    assertThat(builder.setWorkingDirectory(null)).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
+    // then: getDirectory returns that directory
+    assertThat(builder.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
   @Test
-  public void testBuilderSetWorkingDirectoryToFile() throws IOException {
+  public void setWorkingDirectoryToExistingFileThrowsIllegalArgumentException() throws Exception {
     // given: a file instead of a directory
-    File tmpFile = this.temporaryFolder.newFile();
+    File nonDirectory = temporaryFolder.newFile();
 
     // when: setting WorkingDirectory to that file
-    when(new Builder()).setWorkingDirectory(tmpFile.getCanonicalPath());
+    when(new Builder()).setWorkingDirectory(nonDirectory.getCanonicalPath());
 
     // then: throw IllegalArgumentException
     then(caughtException()).isExactlyInstanceOf(IllegalArgumentException.class)
-        .hasMessage(LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
-            .toLocalizedString("Locator"))
-        .hasCause(new FileNotFoundException(tmpFile.getCanonicalPath()));
+        .hasMessage(workingDirectoryNotFoundErrorMessage())
+        .hasCause(new FileNotFoundException(nonDirectory.getCanonicalPath()));
   }
 
   @Test
-  public void testBuildSetWorkingDirectoryToNonCurrentDirectoryOnStart() throws Exception {
-    // given: using LocatorLauncher in-process
-
-    // when: setting WorkingDirectory to non-current directory
-    when(new Builder().setCommand(Command.START).setMemberName("memberOne")
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath())).build();
-
-    // then: throw IllegalStateException
-    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class).hasMessage(
-        LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE
-            .toLocalizedString("Locator"));
-  }
+  public void setWorkingDirectoryToNonExistingDirectory() throws Exception {
+    // given:
 
-  @Test
-  public void testBuilderSetWorkingDirectoryToNonExistingDirectory() {
     // when: setting WorkingDirectory to non-existing directory
     when(new Builder()).setWorkingDirectory("/path/to/non_existing/directory");
 
     // then: throw IllegalArgumentException
     then(caughtException()).isExactlyInstanceOf(IllegalArgumentException.class)
-        .hasMessage(LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
-            .toLocalizedString("Locator"))
+        .hasMessage(workingDirectoryNotFoundErrorMessage())
         .hasCause(new FileNotFoundException("/path/to/non_existing/directory"));
   }
 
+  @Test
+  public void portCanBeOverriddenBySystemProperty() throws Exception {
+    // given: overridden default port
+    int overriddenPort = getRandomAvailableTCPPort();
+    System.setProperty(TEST_OVERRIDE_DEFAULT_PORT_PROPERTY, String.valueOf(overriddenPort));
+
+    // when: creating new LocatorLauncher
+    LocatorLauncher launcher = new Builder().build();
+
+    // then: locator port should be the overridden default port
+    assertThat(launcher.getPort()).isEqualTo(overriddenPort);
+  }
+
+  private String memberNameValidationErrorMessage() {
+    return LocalizedStrings.Launcher_Builder_MEMBER_NAME_VALIDATION_ERROR_MESSAGE
+        .toLocalizedString("Locator");
+  }
+
+  private String workingDirectoryOptionNotValidErrorMessage() {
+    return LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE
+        .toLocalizedString("Locator");
+  }
+
+  private String workingDirectoryNotFoundErrorMessage() {
+    return LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
+        .toLocalizedString("Locator");
+  }
+
+  private File getWorkingDirectory() {
+    return temporaryFolder.getRoot();
+  }
+
+  private String getWorkingDirectoryPath() {
+    try {
+      return getWorkingDirectory().getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private Properties withoutMemberName() {
+    return new Properties();
+  }
+
+  private Properties withMemberName() {
+    Properties properties = new Properties();
+    properties.setProperty(NAME, "locator123");
+    return properties;
+  }
+
   /**
    * Creates a gemfire properties file in temporaryFolder:
    * <ol>
-   * <li>creates <code>fileName</code> in <code>temporaryFolder</code></li>
+   * <li>creates gemfire.properties in <code>temporaryFolder</code></li>
+   * <li>writes config to the file</li>
    * <li>sets "gemfirePropertyFile" system property</li>
-   * <li>writes <code>gemfireProperties</code> to the file</li>
    * </ol>
    */
-  private void useGemFirePropertiesFileInTemporaryFolder(final String fileName,
-      final Properties gemfireProperties) throws Exception {
-    File propertiesFile = new File(this.temporaryFolder.getRoot().getCanonicalPath(), fileName);
-    System.setProperty(DistributedSystem.PROPERTIES_FILE_PROPERTY,
-        propertiesFile.getCanonicalPath());
-
-    gemfireProperties.store(new FileWriter(propertiesFile, false), this.testName.getMethodName());
-    assertThat(propertiesFile.isFile()).isTrue();
-    assertThat(propertiesFile.exists()).isTrue();
+  private void givenGemFirePropertiesFile(final Properties config) {
+    try {
+      String name = GEMFIRE_PREFIX + "properties";
+      File file = new File(getWorkingDirectory(), name);
+      config.store(new FileWriter(file, false), testName.getMethodName());
+      assertThat(file).isFile().exists();
+
+      System.setProperty(PROPERTIES_FILE_PROPERTY, file.getCanonicalPath());
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java
new file mode 100755
index 0000000..c1d2505
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherIntegrationTestCase.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.distributed.AbstractLauncher.Status.STOPPED;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_CONFIGURATION_DIR;
+import static org.apache.geode.distributed.ConfigurationProperties.DISABLE_AUTO_RECONNECT;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.internal.ClusterConfigurationService.CLUSTER_CONFIG_DISK_DIR_PREFIX;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+import static org.apache.geode.internal.DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.ErrorCollector;
+
+import org.apache.geode.distributed.AbstractLauncher.Status;
+import org.apache.geode.distributed.LocatorLauncher.Builder;
+import org.apache.geode.distributed.LocatorLauncher.LocatorState;
+import org.apache.geode.internal.process.ProcessType;
+
+/**
+ * Abstract base class for integration tests of {@link LocatorLauncher}.
+ *
+ * @since GemFire 8.0
+ */
+public abstract class LocatorLauncherIntegrationTestCase extends LauncherIntegrationTestCase {
+
+  protected volatile int defaultLocatorPort;
+  protected volatile int nonDefaultLocatorPort;
+  protected volatile LocatorLauncher launcher;
+
+  private volatile File clusterConfigDirectory;
+
+  @Rule
+  public ErrorCollector errorCollector = new ErrorCollector();
+
+  @Before
+  public void setUpAbstractLocatorLauncherIntegrationTestCase() throws Exception {
+    System.setProperty(GEMFIRE_PREFIX + MCAST_PORT, Integer.toString(0));
+
+    clusterConfigDirectory =
+        temporaryFolder.newFolder(CLUSTER_CONFIG_DISK_DIR_PREFIX + getUniqueName());
+
+    int[] ports = getRandomAvailableTCPPorts(2);
+    defaultLocatorPort = ports[0];
+    nonDefaultLocatorPort = ports[1];
+    System.setProperty(TEST_OVERRIDE_DEFAULT_PORT_PROPERTY, String.valueOf(defaultLocatorPort));
+  }
+
+  @After
+  public void tearDownAbstractLocatorLauncherIntegrationTestCase() throws Exception {
+    if (launcher != null) {
+      launcher.stop();
+    }
+  }
+
+  @Override
+  protected ProcessType getProcessType() {
+    return ProcessType.LOCATOR;
+  }
+
+  @Override
+  protected void givenEmptyWorkingDirectory() {
+    File[] files = getWorkingDirectory().listFiles();
+    assertThat(files).hasSize(1);
+    assertThat(files[0]).isDirectory().isEqualTo(getClusterConfigDirectory());
+  }
+
+  protected LocatorLauncher givenLocatorLauncher() {
+    return givenLocatorLauncher(newBuilder());
+  }
+
+  private LocatorLauncher givenLocatorLauncher(final Builder builder) {
+    return builder.build();
+  }
+
+  protected LocatorLauncher givenRunningLocator() {
+    return givenRunningLocator(newBuilder());
+  }
+
+  protected LocatorLauncher givenRunningLocator(final Builder builder) {
+    return awaitStart(builder);
+  }
+
+  protected LocatorLauncher awaitStart(final LocatorLauncher launcher) {
+    await().atMost(2, MINUTES).until(() -> assertThat(isLauncherOnline()).isTrue());
+    return launcher;
+  }
+
+  protected Locator getLocator() {
+    return launcher.getLocator();
+  }
+
+  /**
+   * Returns a new Builder with helpful defaults for safe testing. If you need a Builder in a test
+   * without any of these defaults then simply use {@code new Builder()} instead.
+   */
+  protected Builder newBuilder() {
+    return new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
+        .setWorkingDirectory(getWorkingDirectoryPath())
+        .set(CLUSTER_CONFIGURATION_DIR, getClusterConfigDirectoryPath())
+        .set(DISABLE_AUTO_RECONNECT, "true").set(LOG_LEVEL, "config").set(MCAST_PORT, "0");
+  }
+
+  protected LocatorLauncher startLocator() {
+    return awaitStart(newBuilder());
+  }
+
+  protected LocatorLauncher startLocator(final Builder builder) {
+    return awaitStart(builder);
+  }
+
+  protected void stopLocator() {
+    assertThat(launcher.stop().getStatus()).isEqualTo(STOPPED);
+  }
+
+  private LocatorLauncher awaitStart(final Builder builder) {
+    launcher = builder.build();
+    assertThat(launcher.start().getStatus()).isEqualTo(Status.ONLINE);
+    return awaitStart(launcher);
+  }
+
+  private File getClusterConfigDirectory() {
+    return clusterConfigDirectory;
+  }
+
+  private String getClusterConfigDirectoryPath() {
+    try {
+      return clusterConfigDirectory.getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private boolean isLauncherOnline() {
+    LocatorState locatorState = launcher.status();
+    assertNotNull(locatorState);
+    return Status.ONLINE.equals(locatorState.getStatus());
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java
new file mode 100644
index 0000000..a465070
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerLocalRegressionTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Set;
+
+import org.awaitility.Awaitility;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.ProcessType;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Regression tests for stopping a JMX Manager process launched with {@link LocatorLauncher}.
+ *
+ * <p>
+ * Confirms fix for <bold>GEODE-528: Locator not stopping correctly if jmx-manager-port=0</bold>
+ *
+ * <p>
+ * Refactored from LocatorLauncherAssemblyIntegrationTest which used to be in geode-assembly.
+ */
+@Category(IntegrationTest.class)
+public class LocatorLauncherJmxManagerLocalRegressionTest
+    extends LocatorLauncherIntegrationTestCase {
+
+  /**
+   * Using Awaitility will increase total thread count by 2: ConditionAwaiter and
+   * ConditionAwaiter$ConditionPoller.
+   */
+  private static final int AWAITILITY_USAGE_THREAD_COUNT = 2;
+
+  private Set<Thread> initialThreads;
+  private int jmxManagerPort;
+
+  @Before
+  public void setUpLocatorLauncherJmxManagerLocalIntegrationTest() throws Exception {
+    disconnectFromDS();
+    System.setProperty(ProcessType.PROPERTY_TEST_PREFIX, getUniqueName() + "-");
+
+    int[] ports = getRandomAvailableTCPPorts(3);
+    this.defaultLocatorPort = ports[0];
+    this.nonDefaultLocatorPort = ports[1];
+    this.jmxManagerPort = ports[2];
+
+    this.initialThreads = Thread.getAllStackTraces().keySet();
+  }
+
+  @Test
+  public void locatorWithZeroJmxPortCleansUpWhenStopped() throws Exception {
+    startLocator(newBuilder().setDeletePidFileOnStop(true).setMemberName(getUniqueName())
+        .setPort(this.defaultLocatorPort).setRedirectOutput(false)
+        .setWorkingDirectory(getWorkingDirectoryPath()).set(LOG_LEVEL, "config")
+        .set(ENABLE_CLUSTER_CONFIGURATION, "false").set(JMX_MANAGER, "true")
+        .set(JMX_MANAGER_START, "true").set(JMX_MANAGER_PORT, "0"));
+
+    stopLocator();
+
+    assertDeletionOf(getPidFile());
+    assertThatThreadsStopped();
+  }
+
+  @Test
+  public void locatorWithNonZeroJmxPortCleansUpWhenStopped() throws Exception {
+    startLocator(newBuilder().setDeletePidFileOnStop(true).setMemberName(getUniqueName())
+        .setPort(this.defaultLocatorPort).setRedirectOutput(false)
+        .setWorkingDirectory(getWorkingDirectoryPath()).set(LOG_LEVEL, "config")
+        .set(ENABLE_CLUSTER_CONFIGURATION, "false").set(JMX_MANAGER, "true")
+        .set(JMX_MANAGER_START, "true").set(JMX_MANAGER_PORT, String.valueOf(jmxManagerPort)));
+
+    stopLocator();
+
+    assertDeletionOf(getPidFile());
+    assertThatThreadsStopped();
+  }
+
+  private void assertThatThreadsStopped() {
+    Awaitility.await().atMost(30, SECONDS).until(
+        () -> assertThat(currentThreadCount()).isEqualTo(initialThreadCountPlusAwaitility()));
+  }
+
+  private int currentThreadCount() {
+    return Thread.getAllStackTraces().keySet().size();
+  }
+
+  private int initialThreadCountPlusAwaitility() {
+    return initialThreads.size() + AWAITILITY_USAGE_THREAD_COUNT;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerRemoteRegressionTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerRemoteRegressionTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerRemoteRegressionTest.java
new file mode 100644
index 0000000..ded6a72
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherJmxManagerRemoteRegressionTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Regression tests for stopping a JMX Manager process launched with {@link LocatorLauncher}.
+ *
+ * <p>
+ * Confirms fix for <bold>GEODE-528: Locator not stopping correctly if jmx-manager-port=0</bold>
+ *
+ * <p>
+ * Refactored from LocatorLauncherAssemblyIntegrationTest which used to be in geode-assembly.
+ */
+@Category(IntegrationTest.class)
+public class LocatorLauncherJmxManagerRemoteRegressionTest
+    extends LocatorLauncherRemoteIntegrationTestCase {
+
+  private int jmxManagerPort;
+
+  @Before
+  public void before() throws Exception {
+    int[] ports = getRandomAvailableTCPPorts(3);
+    this.defaultLocatorPort = ports[0];
+    this.nonDefaultLocatorPort = ports[1];
+    this.jmxManagerPort = ports[2];
+  }
+
+  @Test
+  public void locatorProcessWithZeroJmxPortExitsWhenStopped() throws Exception {
+    givenRunningLocator(addJvmArgument("-D" + JMX_MANAGER + "=true")
+        .addJvmArgument("-D" + JMX_MANAGER_START + "=true")
+        .addJvmArgument("-D" + JMX_MANAGER_PORT + "=0"));
+
+    new LocatorLauncher.Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertStopOf(getLocatorProcess());
+  }
+
+  @Test
+  public void locatorProcessWithNonZeroJmxPortExitsWhenStopped() throws Exception {
+    givenRunningLocator(addJvmArgument("-D" + JMX_MANAGER + "=true")
+        .addJvmArgument("-D" + JMX_MANAGER_START + "=true")
+        .addJvmArgument("-D" + JMX_MANAGER_PORT + "=" + jmxManagerPort));
+
+    new LocatorLauncher.Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertStopOf(getLocatorProcess());
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalFileIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalFileIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalFileIntegrationTest.java
index 86374f1..3ae64c1 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalFileIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalFileIntegrationTest.java
@@ -14,42 +14,29 @@
  */
 package org.apache.geode.distributed;
 
-import org.apache.geode.internal.process.ProcessControllerFactory;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
-import org.junit.After;
+import static org.assertj.core.api.Assertions.assertThat;
+
 import org.junit.Before;
-import org.junit.Test;
 import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
 
-import static org.junit.Assert.assertFalse;
+import org.apache.geode.internal.process.ProcessControllerFactory;
+import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
- * Subclass of LocatorLauncherLocalDUnitTest which forces the code to not find the Attach API which
- * is in the JDK tools.jar. As a result LocatorLauncher ends up using the FileProcessController
- * implementation.
+ * Integration tests for using {@link LocatorLauncher} as an in-process API within an existing JVM
+ * without the Attach API.
+ *
+ * Sets {@link ProcessControllerFactory#PROPERTY_DISABLE_ATTACH_API} to force
+ * {@code LocatorLauncher} to use the FileProcessController implementation.
  *
  * @since GemFire 8.0
  */
 @Category(IntegrationTest.class)
-@RunWith(Parameterized.class)
-@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
 public class LocatorLauncherLocalFileIntegrationTest extends LocatorLauncherLocalIntegrationTest {
 
   @Before
-  public final void setUpLocatorLauncherLocalFileIntegrationTest() throws Exception {
+  public void setUpLocatorLauncherLocalFileIntegrationTest() throws Exception {
     System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true");
-  }
-
-  @After
-  public final void tearDownLocatorLauncherLocalFileIntegrationTest() throws Exception {}
-
-  @Override
-  @Test
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertFalse(factory.isAttachAPIFound());
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isFalse();
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalIntegrationTest.java
index 79314aa..9fce94e 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherLocalIntegrationTest.java
@@ -14,745 +14,269 @@
  */
 package org.apache.geode.distributed;
 
-import org.apache.geode.distributed.AbstractLauncher.Status;
+import static org.apache.geode.distributed.AbstractLauncher.Status.NOT_RESPONDING;
+import static org.apache.geode.distributed.AbstractLauncher.Status.ONLINE;
+import static org.apache.geode.distributed.AbstractLauncher.Status.STOPPED;
+import static org.apache.geode.distributed.ConfigurationProperties.DISABLE_AUTO_RECONNECT;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+import java.net.BindException;
+import java.net.InetAddress;
+import java.util.Collections;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
 import org.apache.geode.distributed.LocatorLauncher.Builder;
 import org.apache.geode.distributed.LocatorLauncher.LocatorState;
 import org.apache.geode.distributed.internal.InternalLocator;
-import org.apache.geode.internal.*;
-import org.apache.geode.internal.net.SocketCreatorFactory;
+import org.apache.geode.internal.GemFireVersion;
 import org.apache.geode.internal.process.ProcessControllerFactory;
 import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.internal.security.SecurableCommunicationChannel;
 import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.io.File;
-import java.lang.management.ManagementFactory;
-import java.net.BindException;
-import java.net.InetAddress;
-
-import static org.apache.geode.distributed.ConfigurationProperties.*;
-import static org.junit.Assert.*;
 
 /**
- * Tests usage of LocatorLauncher as a local API in existing JVM.
+ * Integration tests for using {@link LocatorLauncher} as an in-process API within an existing JVM.
  *
  * @since GemFire 8.0
  */
 @Category(IntegrationTest.class)
-@RunWith(Parameterized.class)
-@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
-public class LocatorLauncherLocalIntegrationTest
-    extends AbstractLocatorLauncherIntegrationTestCase {
+public class LocatorLauncherLocalIntegrationTest extends LocatorLauncherIntegrationTestCase {
 
   @Before
-  public final void setUpLocatorLauncherLocalIntegrationTest() throws Exception {
+  public void setUpLocatorLauncherLocalIntegrationTest() throws Exception {
     disconnectFromDS();
-    System.setProperty(ProcessType.TEST_PREFIX_PROPERTY, getUniqueName() + "-");
+    System.setProperty(ProcessType.PROPERTY_TEST_PREFIX, getUniqueName() + "-");
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isTrue();
   }
 
   @After
-  public final void tearDownLocatorLauncherLocalIntegrationTest() throws Exception {
+  public void tearDownLocatorLauncherLocalIntegrationTest() throws Exception {
     disconnectFromDS();
   }
 
   @Test
-  public void testBuilderSetProperties() throws Throwable {
-    this.launcher = new Builder().setForce(true).setMemberName(getUniqueName())
-        .setPort(this.locatorPort).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory)
-        .set(DISABLE_AUTO_RECONNECT, "true").set(LOG_LEVEL, "config").set(MCAST_PORT, "0").build();
-
-    try {
-      assertEquals(Status.ONLINE, this.launcher.start().getStatus());
-      waitForLocatorToStart(this.launcher, true);
-
-      final InternalLocator locator = this.launcher.getLocator();
-      assertNotNull(locator);
-
-      final DistributedSystem distributedSystem = locator.getDistributedSystem();
-
-      assertNotNull(distributedSystem);
-      assertEquals("true", distributedSystem.getProperties().getProperty(DISABLE_AUTO_RECONNECT));
-      assertEquals("0", distributedSystem.getProperties().getProperty(MCAST_PORT));
-      assertEquals("config", distributedSystem.getProperties().getProperty(LOG_LEVEL));
-      assertEquals(getUniqueName(), distributedSystem.getProperties().getProperty(NAME));
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      assertNull(this.launcher.getLocator());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void usesLocatorPortAsDefaultPort() throws Exception {
+    launcher = givenLocatorLauncher();
+
+    assertThat(launcher.getPort()).isEqualTo(defaultLocatorPort);
   }
 
   @Test
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertTrue(factory.isAttachAPIFound());
+  public void startReturnsOnline() throws Exception {
+    launcher = givenLocatorLauncher();
+
+    assertThat(launcher.start().getStatus()).isEqualTo(ONLINE);
   }
 
   @Test
-  public void testStartCreatesPidFile() throws Throwable {
-    this.launcher = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config")
-        .build();
-
-    try {
-      this.launcher.start();
-      waitForLocatorToStart(this.launcher);
-      assertEquals(Status.ONLINE, this.launcher.status().getStatus());
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      assertEquals(Status.ONLINE, this.launcher.status().getStatus());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithPortUsesPort() throws Exception {
+    LocatorLauncher launcher = startLocator(newBuilder().setPort(defaultLocatorPort));
+
+    assertThat(launcher.getLocator().getPort()).isEqualTo(defaultLocatorPort);
   }
 
   @Test
-  public void testStartDeletesStaleControlFiles() throws Throwable {
-    // create existing control files
-    this.stopRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getStopRequestFileName());
-    this.stopRequestFile.createNewFile();
-    assertTrue(this.stopRequestFile.exists());
-
-    this.statusRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getStatusRequestFileName());
-    this.statusRequestFile.createNewFile();
-    assertTrue(this.statusRequestFile.exists());
-
-    this.statusFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getStatusFileName());
-    this.statusFile.createNewFile();
-    assertTrue(this.statusFile.exists());
-
-    // build and start the locator
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-    this.launcher.start();
-
-    try {
-      waitForLocatorToStart(this.launcher);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      // validate stale control files were deleted
-      assertFalse(stopRequestFile.exists());
-      assertFalse(statusRequestFile.exists());
-      assertFalse(statusFile.exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithPortZeroUsesAnEphemeralPort() throws Exception {
+    LocatorLauncher launcher = startLocator(newBuilder().setPort(0));
+
+    assertThat(launcher.getLocator().getPort()).isGreaterThan(0);
+    assertThat(launcher.getLocator().isPeerLocator()).isTrue();
   }
 
   @Test
-  public void testStartOverwritesStalePidFile() throws Throwable {
-    // create existing pid file
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-    assertFalse("Integer.MAX_VALUE shouldn't be the same as local pid " + Integer.MAX_VALUE,
-        Integer.MAX_VALUE == ProcessUtils.identifyPid());
-    writePid(this.pidFile, Integer.MAX_VALUE);
-
-    // build and start the locator
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-    this.launcher.start();
-
-    try {
-      waitForLocatorToStart(this.launcher);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // validate the pid file and its contents
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startUsesBuilderValues() throws Exception {
+    LocatorLauncher launcher = startLocator(newBuilder().setPort(nonDefaultLocatorPort));
+
+    InternalLocator locator = launcher.getLocator();
+    assertThat(locator.getPort()).isEqualTo(nonDefaultLocatorPort);
+
+    DistributedSystem system = locator.getDistributedSystem();
+    assertThat(system.getProperties().getProperty(DISABLE_AUTO_RECONNECT)).isEqualTo("true");
+    assertThat(system.getProperties().getProperty(LOG_LEVEL)).isEqualTo("config");
+    assertThat(system.getProperties().getProperty(MCAST_PORT)).isEqualTo("0");
+    assertThat(system.getProperties().getProperty(NAME)).isEqualTo(getUniqueName());
   }
 
   @Test
-  @Ignore("Need to rewrite this without using dunit.Host")
-  public void testStartUsingForceOverwritesExistingPidFile() throws Throwable {}
-  /*
-   * assertTrue(getUniqueName() + " is broken if PID == Integer.MAX_VALUE",
-   * ProcessUtils.identifyPid() != Integer.MAX_VALUE);
-   * 
-   * // create existing pid file this.pidFile = new File(ProcessType.LOCATOR.getPidFileName());
-   * final int realPid = Host.getHost(0).getVM(3).invoke(() -> ProcessUtils.identifyPid());
-   * assertFalse(realPid == ProcessUtils.identifyPid()); writePid(this.pidFile, realPid);
-   * 
-   * // build and start the locator final Builder builder = new Builder() .setForce(true)
-   * .setMemberName(getUniqueName()) .setPort(this.locatorPort) .setRedirectOutput(true)
-   * 
-   * assertTrue(builder.getForce()); this.launcher = builder.build();
-   * assertTrue(this.launcher.isForcing()); this.launcher.start();
-   * 
-   * // collect and throw the FIRST failure Throwable failure = null;
-   * 
-   * try { waitForLocatorToStart(this.launcher);
-   * 
-   * // validate the pid file and its contents assertTrue(this.pidFile.exists()); final int pid =
-   * readPid(this.pidFile); assertTrue(pid > 0); assertTrue(ProcessUtils.isProcessAlive(pid));
-   * assertIndexDetailsEquals(getPid(), pid);
-   * 
-   * // validate log file was created final String logFileName = getUniqueName()+".log";
-   * assertTrue("Log file should exist: " + logFileName, new File(logFileName).exists());
-   * 
-   * } catch (Throwable e) { logger.error(e); if (failure == null) { failure = e; } }
-   * 
-   * try { assertIndexDetailsEquals(Status.STOPPED, this.launcher.stop().getStatus());
-   * waitForFileToDelete(this.pidFile); } catch (Throwable e) { logger.error(e); if (failure ==
-   * null) { failure = e; } }
-   * 
-   * if (failure != null) { throw failure; } } // testStartUsingForceOverwritesExistingPidFile
-   */
+  public void startCreatesPidFile() throws Exception {
+    startLocator();
+
+    assertThat(getPidFile()).exists();
+  }
 
   @Test
-  public void testStartWithDefaultPortInUseFails() throws Throwable {
-    // Test makes no sense in this case
-    if (this.locatorPort == 0) {
-      return;
-    }
-
-    this.socket =
-        SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER)
-            .createServerSocket(this.locatorPort, 50, null, -1);
-    assertTrue(this.socket.isBound());
-    assertFalse(this.socket.isClosed());
-    assertFalse(AvailablePort.isPortAvailable(this.locatorPort, AvailablePort.SOCKET));
-
-    assertNotNull(System.getProperty(DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY));
-    assertEquals(this.locatorPort,
-        Integer.valueOf(System.getProperty(DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY))
-            .intValue());
-    assertFalse(AvailablePort.isPortAvailable(this.locatorPort, AvailablePort.SOCKET));
-
-    this.launcher = new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
-        .setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config")
-        .build();
-
-    assertEquals(this.locatorPort, this.launcher.getPort().intValue());
-
-    RuntimeException expected = null;
-    try {
-      this.launcher.start();
-
-      // why did it not fail like it's supposed to?
-      final String property =
-          System.getProperty(DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY);
-      assertNotNull(property);
-      assertEquals(this.locatorPort, Integer.valueOf(property).intValue());
-      assertFalse(AvailablePort.isPortAvailable(this.locatorPort, AvailablePort.SOCKET));
-      assertEquals(this.locatorPort, this.launcher.getPort().intValue());
-      assertEquals(this.locatorPort, this.socket.getLocalPort());
-      assertTrue(this.socket.isBound());
-      assertFalse(this.socket.isClosed());
-
-      fail("LocatorLauncher start should have thrown RuntimeException caused by BindException");
-    } catch (RuntimeException e) {
-      expected = e;
-      assertNotNull(expected.getMessage());
-      // BindException text varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertNotNull(expected);
-      final Throwable cause = expected.getCause();
-      assertNotNull(cause);
-      assertTrue(cause instanceof BindException);
-      // BindException string varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertFalse("Pid file should not exist: " + this.pidFile, this.pidFile.exists());
-
-      // creation of log file seems to be random -- look into why sometime
-      final String logFileName = getUniqueName() + ".log";
-      assertFalse("Log file should not exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // just in case the launcher started...
-    LocatorState status = null;
-    try {
-      status = this.launcher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
-
-    try {
-      waitForFileToDelete(this.pidFile);
-      assertEquals(getExpectedStopStatusForNotRunning(), status.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void pidFileContainsServerPid() throws Exception {
+    startLocator();
+
+    assertThat(getLocatorPid()).isEqualTo(localPid);
   }
 
   @Test
-  @Ignore("Need to rewrite this without using dunit.Host")
-  public void testStartWithExistingPidFileFails()
-      throws Throwable {}/*
-                          * // create existing pid file final int realPid =
-                          * Host.getHost(0).getVM(3).invoke(() -> ProcessUtils.identifyPid());
-                          * assertFalse("Remote pid shouldn't be the same as local pid " + realPid,
-                          * realPid == ProcessUtils.identifyPid());
-                          * 
-                          * this.pidFile = new File(ProcessType.LOCATOR.getPidFileName());
-                          * writePid(this.pidFile, realPid);
-                          * 
-                          * // build and start the locator final Builder builder = new Builder()
-                          * .setMemberName(getUniqueName()) .setPort(this.locatorPort)
-                          * .setRedirectOutput(true) .set(logLevel, "config");
-                          * 
-                          * assertFalse(builder.getForce()); this.launcher = builder.build();
-                          * assertFalse(this.launcher.isForcing());
-                          * 
-                          * // collect and throw the FIRST failure Throwable failure = null;
-                          * RuntimeException expected = null;
-                          * 
-                          * try { this.launcher.start();
-                          * fail("LocatorLauncher start should have thrown RuntimeException caused by FileAlreadyExistsException"
-                          * ); } catch (RuntimeException e) { expected = e;
-                          * assertNotNull(expected.getMessage()); assertTrue(expected.getMessage(),
-                          * expected.getMessage().
-                          * contains("A PID file already exists and a Locator may be running in"));
-                          * assertIndexDetailsEquals(RuntimeException.class, expected.getClass()); }
-                          * catch (Throwable e) { logger.error(e); if (failure == null) { failure =
-                          * e; } }
-                          * 
-                          * // just in case the launcher started... LocatorState status = null; try
-                          * { status = this.launcher.stop(); } catch (Throwable t) { // ignore }
-                          * 
-                          * try { assertNotNull(expected); final Throwable cause =
-                          * expected.getCause(); assertNotNull(cause); assertTrue(cause instanceof
-                          * FileAlreadyExistsException);
-                          * assertTrue(cause.getMessage().contains("Pid file already exists: "));
-                          * assertTrue(cause.getMessage().contains("vf.gf.locator.pid for process "
-                          * + realPid)); } catch (Throwable e) { logger.error(e); if (failure ==
-                          * null) { failure = e; } }
-                          * 
-                          * try { delete(this.pidFile); final Status theStatus = status.getStatus();
-                          * assertFalse(theStatus == Status.STARTING); assertFalse(theStatus ==
-                          * Status.ONLINE); } catch (Throwable e) { logger.error(e); if (failure ==
-                          * null) { failure = e; } }
-                          * 
-                          * if (failure != null) { throw failure; } } //
-                          * testStartWithExistingPidFileFails
-                          */
+  public void startDeletesStaleControlFiles() throws Exception {
+    File stopRequestFile = givenControlFile(getProcessType().getStopRequestFileName());
+    File statusRequestFile = givenControlFile(getProcessType().getStatusRequestFileName());
+    File statusFile = givenControlFile(getProcessType().getStatusFileName());
+
+    startLocator();
+
+    assertDeletionOf(stopRequestFile);
+    assertDeletionOf(statusRequestFile);
+    assertDeletionOf(statusFile);
+  }
 
   @Test
-  public void testStartUsingPort() throws Throwable {
-    // generate one free port and then use it instead of default
-    final int freeTCPPort = AvailablePortHelper.getRandomAvailableTCPPort();
-    assertTrue(AvailablePort.isPortAvailable(freeTCPPort, AvailablePort.SOCKET));
-
-    this.launcher = new Builder().setMemberName(getUniqueName()).setPort(freeTCPPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config")
-        .build();
-
-    int pid = 0;
-    try {
-      // if start succeeds without throwing exception then #47778 is fixed
-      this.launcher.start();
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(pidFile.exists());
-      pid = readPid(pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertEquals(getPid(), pid);
-
-      // verify locator did not use default port
-      assertTrue(AvailablePort.isPortAvailable(this.locatorPort, AvailablePort.SOCKET));
-
-      final LocatorState status = this.launcher.status();
-      final String portString = status.getPort();
-      assertEquals("Port should be \"" + freeTCPPort + "\" instead of " + portString,
-          String.valueOf(freeTCPPort), portString);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startOverwritesStalePidFile() throws Exception {
+    givenPidFile(fakePid);
+
+    startLocator();
+
+    assertThat(getLocatorPid()).isNotEqualTo(fakePid);
   }
 
   @Test
-  public void testStartUsingPortInUseFails() throws Throwable {
-    // Test makes no sense in this case
-    if (this.locatorPort == 0) {
-      return;
-    }
-
-    // generate one free port and then use it instead of default
-    this.socket =
-        SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.CLUSTER)
-            .createServerSocket(this.locatorPort, 50, null, -1);
-
-    this.launcher = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config")
-        .build();
-
-    RuntimeException expected = null;
-    try {
-      this.launcher.start();
-      fail("LocatorLauncher start should have thrown RuntimeException caused by BindException");
-    } catch (RuntimeException e) {
-      expected = e;
-      assertNotNull(expected.getMessage());
-      // BindException string varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertNotNull(expected);
-      final Throwable cause = expected.getCause();
-      assertNotNull(cause);
-      assertTrue(cause instanceof BindException);
-      // BindException string varies by platform
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertFalse("Pid file should not exist: " + this.pidFile, this.pidFile.exists());
-
-      // creation of log file seems to be random -- look into why sometime
-      final String logFileName = getUniqueName() + ".log";
-      assertFalse("Log file should not exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // just in case the launcher started...
-    LocatorState status = null;
-    try {
-      status = this.launcher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
-
-    try {
-      waitForFileToDelete(this.pidFile);
-      assertEquals(getExpectedStopStatusForNotRunning(), status.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithDefaultPortInUseFailsWithBindException() throws Exception {
+    givenLocatorPortInUse(defaultLocatorPort);
+
+    launcher = new Builder().build();
+
+    assertThatThrownBy(() -> launcher.start()).isInstanceOf(RuntimeException.class)
+        .hasCauseInstanceOf(BindException.class);
+  }
+
+  @Test
+  public void startWithLocatorPortInUseFailsWithBindException() throws Exception {
+    givenServerPortInUse(nonDefaultLocatorPort);
+
+    launcher = new Builder().setPort(nonDefaultLocatorPort).build();
+
+    assertThatThrownBy(() -> this.launcher.start()).isInstanceOf(RuntimeException.class)
+        .hasCauseInstanceOf(BindException.class);
+  }
+
+  @Test
+  public void statusWithPidReturnsOnlineWithDetails() throws Exception {
+    givenRunningLocator();
+
+    LocatorState locatorState = new Builder().setPid(localPid).build().status();
+
+    assertThat(locatorState.getStatus()).isEqualTo(ONLINE);
+    assertThat(locatorState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(locatorState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(locatorState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(locatorState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(locatorState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(locatorState.getLogFile()).isEqualTo(getLogFilePath());
+    assertThat(locatorState.getMemberName()).isEqualTo(getUniqueName());
+    assertThat(locatorState.getPid().intValue()).isEqualTo(localPid);
+    assertThat(locatorState.getUptime()).isGreaterThan(0);
+    assertThat(locatorState.getWorkingDirectory()).isEqualTo(new File(".").getCanonicalPath());
+  }
+
+  @Test
+  public void statusWithWorkingDirectoryReturnsOnlineWithDetails() throws Exception {
+    givenRunningLocator();
+
+    LocatorState locatorState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(locatorState.getStatus()).isEqualTo(ONLINE);
+    assertThat(locatorState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(locatorState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(locatorState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(locatorState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(locatorState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(locatorState.getLogFile()).isEqualTo(getLogFilePath());
+    assertThat(locatorState.getMemberName()).isEqualTo(getUniqueName());
+    assertThat(locatorState.getPid().intValue()).isEqualTo(readPidFile());
+    assertThat(locatorState.getUptime()).isGreaterThan(0);
+    assertThat(locatorState.getWorkingDirectory()).isEqualTo(new File(".").getCanonicalPath());
+  }
+
+  @Test
+  public void statusWithEmptyPidFileThrowsIllegalArgumentException() throws Exception {
+    givenEmptyPidFile();
+
+    LocatorLauncher launcher = new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build();
+
+    assertThatThrownBy(() -> launcher.status()).isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid pid 'null' found in");
   }
 
   @Test
-  public void testStatusUsingPid() throws Throwable {
-    // build and start the locator
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    LocatorLauncher pidLauncher = null;
-    try {
-      this.launcher.start();
-      waitForLocatorToStart(this.launcher);
-
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue("Pid file " + this.pidFile.getCanonicalPath().toString() + " should exist",
-          this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      pidLauncher = new Builder().setPid(pid).build();
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      final LocatorState actualStatus = pidLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      // getWorkingDirectory returns user.dir instead of rootFolder because test is starting Locator
-      // in this process (to move logFile and pidFile into temp dir)
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(this.workingDirectory + File.separator + getUniqueName() + ".log",
-          actualStatus.getLogFile());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    if (pidLauncher == null) {
-      try {
-        assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-
-    } else {
-      try {
-        assertEquals(Status.STOPPED, pidLauncher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-    }
+  public void statusWithEmptyWorkingDirectoryReturnsNotRespondingWithDetails() throws Exception {
+    givenEmptyWorkingDirectory();
+
+    LocatorState locatorState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(locatorState.getStatus()).isEqualTo(NOT_RESPONDING);
+    assertThat(locatorState.getClasspath()).isNull();
+    assertThat(locatorState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(locatorState.getHost()).isNull();
+    assertThat(locatorState.getJavaVersion()).isNull();
+    assertThat(locatorState.getJvmArguments()).isEqualTo(Collections.emptyList());
+    assertThat(locatorState.getLogFile()).isNull();
+    assertThat(locatorState.getMemberName()).isNull();
+    assertThat(locatorState.getPid()).isNull();
+    assertThat(locatorState.getUptime().intValue()).isEqualTo(0);
+    assertThat(locatorState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
+  /**
+   * This test takes > 1 minute to run in {@link LocatorLauncherLocalFileIntegrationTest}.
+   */
   @Test
-  public void testStatusUsingWorkingDirectory() throws Throwable {
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    LocatorLauncher dirLauncher = null;
-    try {
-      this.launcher.start();
-      waitForLocatorToStart(this.launcher);
-
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue("Pid file " + this.pidFile.getCanonicalPath().toString() + " should exist",
-          this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      dirLauncher = new Builder().setWorkingDirectory(this.workingDirectory).build();
-      assertNotNull(dirLauncher);
-      assertFalse(dirLauncher.isRunning());
-
-      final LocatorState actualStatus = dirLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      // getWorkingDirectory returns user.dir instead of rootFolder because test is starting Locator
-      // in this process (to move logFile and pidFile into temp dir)
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(this.workingDirectory + File.separator + getUniqueName() + ".log",
-          actualStatus.getLogFile());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    if (dirLauncher == null) {
-      try {
-        assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-
-    } else {
-      try {
-        assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-        waitForFileToDelete(this.pidFile);
-      } catch (Throwable e) {
-        this.errorCollector.addError(e);
-      }
-    }
+  public void statusWithStalePidFileReturnsNotResponding() throws Exception {
+    givenPidFile(fakePid);
+
+    LocatorState locatorState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(locatorState.getStatus()).isEqualTo(NOT_RESPONDING);
   }
 
   @Test
-  public void testStopUsingPid() throws Throwable {
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    LocatorLauncher pidLauncher = null;
-    try {
-      this.launcher.start();
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      pidLauncher = new Builder().setPid(pid).build();
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      // stop the locator
-      final LocatorState locatorState = pidLauncher.stop();
-      assertNotNull(locatorState);
-      assertEquals(Status.STOPPED, locatorState.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.launcher.stop();
-    } catch (Throwable e) {
-      // ignore
-    }
-
-    try {
-      // verify the PID file was deleted
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void stopWithPidReturnsStopped() throws Exception {
+    givenRunningLocator();
+
+    LocatorState locatorState = new Builder().setPid(localPid).build().stop();
+
+    assertThat(locatorState.getStatus()).isEqualTo(STOPPED);
   }
 
   @Test
-  public void testStopUsingWorkingDirectory() throws Throwable {
-    final Builder builder = new Builder().setMemberName(getUniqueName()).setPort(this.locatorPort)
-        .setRedirectOutput(true).setWorkingDirectory(this.workingDirectory)
-        .set(CLUSTER_CONFIGURATION_DIR, this.clusterConfigDirectory).set(LOG_LEVEL, "config");
-
-    assertFalse(builder.getForce());
-    this.launcher = builder.build();
-    assertFalse(this.launcher.isForcing());
-
-    LocatorLauncher dirLauncher = null;
-    try {
-      this.launcher.start();
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue("Pid file " + this.pidFile.getCanonicalPath().toString() + " should exist",
-          this.pidFile.exists());
-      final int pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertEquals(ProcessUtils.identifyPid(), pid);
-
-      dirLauncher = new Builder().setWorkingDirectory(this.workingDirectory).build();
-      assertNotNull(dirLauncher);
-      assertFalse(dirLauncher.isRunning());
-
-      // stop the locator
-      final LocatorState locatorState = dirLauncher.stop();
-      assertNotNull(locatorState);
-      assertEquals(Status.STOPPED, locatorState.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      this.launcher.stop();
-    } catch (Throwable e) {
-      // ignore
-    }
-
-    try {
-      // verify the PID file was deleted
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void stopWithPidDeletesPidFile() throws Exception {
+    givenRunningLocator(newBuilder().setDeletePidFileOnStop(true));
+
+    new Builder().setPid(localPid).build().stop();
+
+    assertDeletionOf(getPidFile());
+  }
+
+  @Test
+  public void stopWithWorkingDirectoryReturnsStopped() throws Exception {
+    givenRunningLocator();
+
+    LocatorState locatorState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertThat(locatorState.getStatus()).isEqualTo(STOPPED);
+  }
+
+  @Test
+  public void stopWithWorkingDirectoryDeletesPidFile() throws Exception {
+    givenRunningLocator(newBuilder().setDeletePidFileOnStop(true));
+
+    new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertDeletionOf(getPidFile());
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteFileIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteFileIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteFileIntegrationTest.java
index 9e86c8c..6bfba2d 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteFileIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteFileIntegrationTest.java
@@ -14,214 +14,69 @@
  */
 package org.apache.geode.distributed;
 
-import static org.junit.Assert.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.distributed.AbstractLauncher.Status;
 import org.apache.geode.distributed.LocatorLauncher.Builder;
 import org.apache.geode.internal.process.ProcessControllerFactory;
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
 import org.apache.geode.lang.AttachAPINotFoundException;
 import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
 
 /**
- * Subclass of LocatorLauncherRemoteDUnitTest which forces the code to not find the Attach API which
- * is in the JDK tools.jar. As a result LocatorLauncher ends up using the FileProcessController
- * implementation.
- * 
+ * Integration tests for using {@code LocatorLauncher} as an application main in a forked JVM
+ * without the Attach API.
+ *
+ * Sets {@link ProcessControllerFactory#PROPERTY_DISABLE_ATTACH_API} to force
+ * {@code LocatorLauncher} to use the FileProcessController implementation.
+ *
  * @since GemFire 8.0
  */
 @Category(IntegrationTest.class)
-@RunWith(Parameterized.class)
-@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
 public class LocatorLauncherRemoteFileIntegrationTest extends LocatorLauncherRemoteIntegrationTest {
 
   @Before
-  public final void setUpLocatorLauncherRemoteFileIntegrationTest() throws Exception {
+  public void setUpLocatorLauncherRemoteFileIntegrationTest() throws Exception {
     System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true");
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isFalse();
   }
 
-  @After
-  public final void tearDownLocatorLauncherRemoteFileIntegrationTest() throws Exception {}
-
-  /**
-   * Override and assert Attach API is NOT found
-   */
-  @Override
   @Test
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertFalse(factory.isAttachAPIFound());
-  }
-
-  /**
-   * Override because FileProcessController cannot request status with PID
-   */
   @Override
-  @Test
-  public void testStatusUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for locator to start
-    int pid = 0;
-    LocatorLauncher pidLauncher = null;
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(dirLauncher);
-
-      // validate the pid file and its contents
-      final File pidFile =
-          new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(pidFile.exists());
-      pid = readPid(pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
-
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
+  public void statusWithPidReturnsOnlineWithDetails() throws Exception {
+    givenRunningLocator();
 
-      // status with pid only should throw AttachAPINotFoundException
-      try {
-        pidLauncher.status();
-        fail("FileProcessController should have thrown AttachAPINotFoundException");
-      } catch (AttachAPINotFoundException e) {
-        // passed
-      }
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-      waitForPidToStop(pid, true);
-      waitForFileToDelete(this.pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThatThrownBy(() -> new Builder().setPid(getLocatorPid()).build().status())
+        .isInstanceOf(AttachAPINotFoundException.class);
   }
 
-  /**
-   * Override because FileProcessController cannot request stop with PID
-   */
-  @Override
   @Test
-  public void testStopUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(createLoggingListener("sysout", getUniqueName() + "#sysout")).build()
-            .start();
-    this.processErrReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(createLoggingListener("syserr", getUniqueName() + "#syserr")).build()
-            .start();
-
-    // wait for locator to start
-    int pid = 0;
-    File pidFile = null;
-    LocatorLauncher pidLauncher = null;
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(dirLauncher);
-
-      // validate the pid file and its contents
-      pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(pidFile.exists());
-      pid = readPid(pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
+  @Override
+  public void stopWithPidDeletesPidFile() throws Exception {
+    givenRunningLocator();
 
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
+    assertThatThrownBy(() -> new Builder().setPid(getLocatorPid()).build().stop())
+        .isInstanceOf(AttachAPINotFoundException.class);
+  }
 
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
+  @Test
+  @Override
+  public void stopWithPidReturnsStopped() throws Exception {
+    givenRunningLocator();
 
-      // stop with pid only should throw AttachAPINotFoundException
-      try {
-        pidLauncher.stop();
-        fail("FileProcessController should have thrown AttachAPINotFoundException");
-      } catch (AttachAPINotFoundException e) {
-        // passed
-      }
+    assertThatThrownBy(() -> new Builder().setPid(getLocatorPid()).build().stop())
+        .isInstanceOf(AttachAPINotFoundException.class);
+  }
 
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  @Test
+  @Override
+  public void stopWithPidStopsLocatorProcess() throws Exception {
+    givenRunningLocator();
 
-    try {
-      // stop the locator
-      assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-      waitForPidToStop(pid);
-      waitForFileToDelete(pidFile);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThatThrownBy(() -> new Builder().setPid(getLocatorPid()).build().stop())
+        .isInstanceOf(AttachAPINotFoundException.class);
   }
 }


[12/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherTest.java
index e28421d..2bcd994 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherTest.java
@@ -14,932 +14,296 @@
  */
 package org.apache.geode.distributed;
 
-import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.atLeast;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.util.Collections;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
 import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.server.CacheServer;
 import org.apache.geode.distributed.ServerLauncher.Builder;
-import org.apache.geode.distributed.ServerLauncher.Command;
-import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.distributed.support.DistributedSystemAdapter;
 import org.apache.geode.internal.cache.CacheConfig;
-import org.apache.geode.internal.i18n.LocalizedStrings;
-import org.apache.geode.test.junit.categories.FlakyTest;
 import org.apache.geode.test.junit.categories.UnitTest;
-import org.jmock.Expectations;
-import org.jmock.Mockery;
-import org.jmock.lib.concurrent.Synchroniser;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.contrib.java.lang.system.RestoreSystemProperties;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
-
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collections;
-import java.util.concurrent.atomic.AtomicBoolean;
-import edu.umd.cs.mtc.MultithreadedTestCase;
-import edu.umd.cs.mtc.TestFramework;
 
 /**
- * The ServerLauncherTest class is a test suite of unit tests testing the contract, functionality
- * and invariants of the ServerLauncher class.
+ * Unit tests for {@link ServerLauncher}.
  *
- * @see org.apache.geode.distributed.ServerLauncher
- * @see org.apache.geode.distributed.ServerLauncher.Builder
- * @see org.apache.geode.distributed.ServerLauncher.Command
- * @see org.junit.Assert
- * @see org.junit.Test
  * @since GemFire 7.0
  */
-@SuppressWarnings({"deprecation", "unused"})
 @Category(UnitTest.class)
 public class ServerLauncherTest {
 
-  private Mockery mockContext;
-
-  @Rule
-  public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
-
-  @Rule
-  public final TestName testName = new TestName();
-
   @Before
-  public void setup() {
-    mockContext = new Mockery() {
-      {
-        setImposteriser(ClassImposteriser.INSTANCE);
-        setThreadingPolicy(new Synchroniser());
-      }
-    };
+  public void before() throws Exception {
     DistributedSystem.removeSystem(InternalDistributedSystem.getConnectedInstance());
   }
 
-  @After
-  public void tearDown() {
-    mockContext.assertIsSatisfied();
-    mockContext = null;
-  }
-
-  @Test
-  public void shouldBeMockable() throws Exception {
-    ServerLauncher mockServerLauncher = mock(ServerLauncher.class);
-    Cache mockCache = mock(Cache.class);
-    CacheConfig mockCacheConfig = mock(CacheConfig.class);
-
-    when(mockServerLauncher.getCache()).thenReturn(mockCache);
-    when(mockServerLauncher.getCacheConfig()).thenReturn(mockCacheConfig);
-    when(mockServerLauncher.getId()).thenReturn("ID");
-    when(mockServerLauncher.isWaiting(eq(mockCache))).thenReturn(true);
-    when(mockServerLauncher.isHelping()).thenReturn(true);
-
-    mockServerLauncher.startCacheServer(mockCache);
-
-    verify(mockServerLauncher, times(1)).startCacheServer(mockCache);
-
-    assertThat(mockServerLauncher.getCache()).isSameAs(mockCache);
-    assertThat(mockServerLauncher.getCacheConfig()).isSameAs(mockCacheConfig);
-    assertThat(mockServerLauncher.getId()).isSameAs("ID");
-    assertThat(mockServerLauncher.isWaiting(mockCache)).isTrue();
-    assertThat(mockServerLauncher.isHelping()).isTrue();
-  }
-
   @Test
-  public void testParseCommand() {
-    Builder builder = new Builder();
-
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
-
-    builder.parseCommand((String[]) null);
-
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
-
-    builder.parseCommand(); // empty String array
-
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
-
-    builder.parseCommand(Command.START.getName());
-
-    assertEquals(Command.START, builder.getCommand());
+  public void canBeMocked() throws Exception {
+    ServerLauncher launcher = mock(ServerLauncher.class);
+    Cache cache = mock(Cache.class);
+    CacheConfig cacheConfig = mock(CacheConfig.class);
 
-    builder.parseCommand("Status");
+    when(launcher.getCache()).thenReturn(cache);
+    when(launcher.getCacheConfig()).thenReturn(cacheConfig);
+    when(launcher.getId()).thenReturn("ID");
+    when(launcher.isWaiting(eq(cache))).thenReturn(true);
+    when(launcher.isHelping()).thenReturn(true);
 
-    assertEquals(Command.STATUS, builder.getCommand());
+    launcher.startCacheServer(cache);
 
-    builder.parseCommand("sToP");
+    verify(launcher, times(1)).startCacheServer(cache);
 
-    assertEquals(Command.STOP, builder.getCommand());
-
-    builder.parseCommand("--opt", "START", "-o", Command.STATUS.getName());
-
-    assertEquals(Command.START, builder.getCommand());
-
-    builder.setCommand(null);
-    builder.parseCommand("badCommandName", "--start", "stat");
-
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
+    assertThat(launcher.getCache()).isSameAs(cache);
+    assertThat(launcher.getCacheConfig()).isSameAs(cacheConfig);
+    assertThat(launcher.getId()).isSameAs("ID");
+    assertThat(launcher.isWaiting(cache)).isTrue();
+    assertThat(launcher.isHelping()).isTrue();
   }
 
   @Test
-  public void testParseMemberName() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getMemberName());
-
-    builder.parseMemberName((String[]) null);
-
-    assertNull(builder.getMemberName());
-
-    builder.parseMemberName(); // empty String array
+  public void isServingReturnsTrueWhenCacheHasOneCacheServer() throws Exception {
+    Cache cache = mock(Cache.class);
+    CacheServer cacheServer = mock(CacheServer.class);
+    when(cache.getCacheServers()).thenReturn(Collections.singletonList(cacheServer));
 
-    assertNull(builder.getMemberName());
+    ServerLauncher launcher = new Builder().build();
 
-    builder.parseMemberName(Command.START.getName(), "--opt", "-o");
-
-    assertNull(builder.getMemberName());
-
-    builder.parseMemberName("memberOne");
-
-    assertEquals("memberOne", builder.getMemberName());
+    assertThat(launcher.isServing(cache)).isTrue();
   }
 
   @Test
-  public void testSetAndGetCommand() {
-    Builder builder = new Builder();
-
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
-    assertSame(builder, builder.setCommand(Command.STATUS));
-    assertEquals(Command.STATUS, builder.getCommand());
-    assertSame(builder, builder.setCommand(null));
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
-  }
+  public void isServingReturnsFalseWhenCacheHasZeroCacheServers() throws Exception {
+    Cache cache = mock(Cache.class);
+    when(cache.getCacheServers()).thenReturn(Collections.emptyList());
 
-  @Test
-  public void testSetAndGetMemberName() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getMemberName());
-    assertSame(builder, builder.setMemberName("serverOne"));
-    assertEquals("serverOne", builder.getMemberName());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMemberNameToBlankString() {
-    try {
-      new Builder().setMemberName("  ");
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE.toLocalizedString("Server"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
+    ServerLauncher launcher = new Builder().build();
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMemberNameToEmptyString() {
-    try {
-      new Builder().setMemberName("");
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE.toLocalizedString("Server"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMemberNameToNullString() {
-    try {
-      new Builder().setMemberName(null);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE.toLocalizedString("Server"),
-          expected.getMessage());
-      throw expected;
-    }
+    assertThat(launcher.isServing(cache)).isFalse();
   }
 
   @Test
-  public void testSetAndGetPid() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getPid());
-    assertSame(builder, builder.setPid(0));
-    assertEquals(0, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(1));
-    assertEquals(1, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(1024));
-    assertEquals(1024, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(12345));
-    assertEquals(12345, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(null));
-    assertNull(builder.getPid());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetPidToInvalidValue() {
-    try {
-      new Builder().setPid(-1);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(LocalizedStrings.Launcher_Builder_PID_ERROR_MESSAGE.toLocalizedString(),
-          expected.getMessage());
-      throw expected;
-    }
-  }
+  public void reconnectedCacheIsClosed() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    Cache reconnectedCache = mock(Cache.class, "ReconnectedCache");
+    when(cache.isReconnecting()).thenReturn(false).thenReturn(false).thenReturn(true);
+    when(cache.getCacheServers()).thenReturn(Collections.emptyList());
+    when(cache.getReconnectedCache()).thenReturn(reconnectedCache);
 
-  @Test
-  public void testSetAndGetServerBindAddress() throws Exception {
-    Builder builder = new Builder();
-
-    assertNull(builder.getServerBindAddress());
-    assertSame(builder, builder.setServerBindAddress(null));
-    assertNull(builder.getServerBindAddress());
-    assertSame(builder, builder.setServerBindAddress(""));
-    assertNull(builder.getServerBindAddress());
-    assertSame(builder, builder.setServerBindAddress("  "));
-    assertNull(builder.getServerBindAddress());
-    assertSame(builder,
-        builder.setServerBindAddress(InetAddress.getLocalHost().getCanonicalHostName()));
-    assertEquals(InetAddress.getLocalHost(), builder.getServerBindAddress());
-  }
+    new Builder().setCache(cache).build().waitOnServer();
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetServerBindAddressToUnknownHost() {
-    try {
-      new Builder().setServerBindAddress("badHostName.badCompany.com");
-    } catch (IllegalArgumentException expected) {
-      final String expectedMessage1 =
-          LocalizedStrings.Launcher_Builder_UNKNOWN_HOST_ERROR_MESSAGE.toLocalizedString("Server");
-      final String expectedMessage2 =
-          "badHostName.badCompany.com is not an address for this machine.";
-      assertTrue(expected.getMessage().equals(expectedMessage1)
-          || expected.getMessage().equals(expectedMessage2));
-      if (expected.getMessage().equals(expectedMessage1)) {
-        assertTrue(expected.getCause() instanceof UnknownHostException);
-      }
-      throw expected;
-    }
-  }
-
-  @Category(FlakyTest.class) // GEODE-1309
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetServerBindAddressToNonLocalHost() {
-    try {
-      new Builder().setServerBindAddress("yahoo.com");
-    } catch (IllegalArgumentException expected) {
-      final String expectedMessage = "yahoo.com is not an address for this machine.";
-      assertEquals(expectedMessage, expected.getMessage());
-      throw expected;
-    }
+    verify(cache, atLeast(3)).isReconnecting();
+    verify(cache).getReconnectedCache();
+    verify(reconnectedCache).close();
   }
 
   @Test
-  public void testSetServerBindAddressToLocalHost() throws Exception {
-    String host = InetAddress.getLocalHost().getHostName();
-    new Builder().setServerBindAddress(host);
-  }
+  public void isRunningReturnsTrueWhenRunningIsSetTrue() throws Exception {
+    ServerLauncher launcher = new Builder().build();
 
-  @Test
-  public void testSetAndGetHostnameForClients() {
-    final Builder builder = new Builder();
+    launcher.running.set(true);
 
-    assertNull(builder.getHostNameForClients());
-    assertSame(builder, builder.setHostNameForClients("Pegasus"));
-    assertEquals("Pegasus", builder.getHostNameForClients());
+    assertThat(launcher.isRunning()).isTrue();
   }
 
   @Test
-  public void testSetAndGetServerPort() {
-    Builder builder = new Builder();
-
-    assertEquals(Integer.valueOf(CacheServer.DEFAULT_PORT), builder.getServerPort());
-    assertSame(builder, builder.setServerPort(0));
-    assertEquals(0, builder.getServerPort().intValue());
-    assertSame(builder, builder.setServerPort(1));
-    assertEquals(1, builder.getServerPort().intValue());
-    assertSame(builder, builder.setServerPort(80));
-    assertEquals(80, builder.getServerPort().intValue());
-    assertSame(builder, builder.setServerPort(1024));
-    assertEquals(1024, builder.getServerPort().intValue());
-    assertSame(builder, builder.setServerPort(65535));
-    assertEquals(65535, builder.getServerPort().intValue());
-    assertSame(builder, builder.setServerPort(null));
-    assertEquals(Integer.valueOf(CacheServer.DEFAULT_PORT), builder.getServerPort());
-  }
+  public void isRunningReturnsFalseWhenRunningIsSetFalse() throws Exception {
+    ServerLauncher launcher = new Builder().build();
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetServerPortToOverflow() {
-    try {
-      new Builder().setServerPort(65536);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_INVALID_PORT_ERROR_MESSAGE.toLocalizedString("Server"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
+    launcher.running.set(false);
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetServerPortToUnderflow() {
-    try {
-      new Builder().setServerPort(-1);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_INVALID_PORT_ERROR_MESSAGE.toLocalizedString("Server"),
-          expected.getMessage());
-      throw expected;
-    }
+    assertThat(launcher.isRunning()).isFalse();
   }
 
   @Test
-  public void testSetAndGetCriticalHeapPercentage() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getCriticalHeapPercentage());
-    assertSame(builder, builder.setCriticalHeapPercentage(55.5f));
-    assertEquals(55.5f, builder.getCriticalHeapPercentage().floatValue(), 0.0f);
-    assertSame(builder, builder.setCriticalHeapPercentage(null));
-    assertNull(builder.getCriticalHeapPercentage());
-  }
+  public void reconnectingDistributedSystemIsDisconnectedOnStop() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    DistributedSystem system = mock(DistributedSystem.class, "DistributedSystem");
+    Cache reconnectedCache = mock(Cache.class, "ReconnectedCache");
+    when(cache.isReconnecting()).thenReturn(true);
+    when(cache.getReconnectedCache()).thenReturn(reconnectedCache);
+    when(reconnectedCache.isReconnecting()).thenReturn(true);
+    when(reconnectedCache.getReconnectedCache()).thenReturn(null);
+    when(reconnectedCache.getDistributedSystem()).thenReturn(system);
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetCriticalHeapPercentageToOverflow() {
-    try {
-      new Builder().setCriticalHeapPercentage(100.01f);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Critical heap percentage (100.01) must be between 0 and 100!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
+    ServerLauncher launcher = new Builder().setCache(cache).build();
+    launcher.running.set(true);
+    launcher.stop();
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetCriticalHeapPercentageToUnderflow() {
-    try {
-      new Builder().setCriticalHeapPercentage(-0.01f);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Critical heap percentage (-0.01) must be between 0 and 100!",
-          expected.getMessage());
-      throw expected;
-    }
+    verify(cache, times(1)).isReconnecting();
+    verify(cache, times(1)).getReconnectedCache();
+    verify(cache, times(1)).isReconnecting();
+    verify(cache, times(1)).getReconnectedCache();
+    verify(reconnectedCache, times(1)).getDistributedSystem();
+    verify(system, times(1)).stopReconnecting();
+    verify(reconnectedCache, times(1)).close();
   }
 
   @Test
-  public void testSetAndGetEvictionHeapPercentage() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getEvictionHeapPercentage());
-    assertSame(builder, builder.setEvictionHeapPercentage(55.55f));
-    assertEquals(55.55f, builder.getEvictionHeapPercentage().floatValue(), 0.0f);
-    assertSame(builder, builder.setEvictionHeapPercentage(null));
-    assertNull(builder.getEvictionHeapPercentage());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetEvictionHeapPercentageToOverflow() {
-    try {
-      new Builder().setEvictionHeapPercentage(101.0f);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Eviction heap percentage (101.0) must be between 0 and 100!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetEvictionHeapPercentageToUnderflow() {
-    try {
-      new Builder().setEvictionHeapPercentage(-10.0f);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Eviction heap percentage (-10.0) must be between 0 and 100!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
+  public void isWaitingReturnsTrueWhenSystemIsConnected() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    DistributedSystem system = mock(DistributedSystem.class, "DistributedSystem");
+    when(cache.getDistributedSystem()).thenReturn(system);
+    when(system.isConnected()).thenReturn(true);
 
-  @Test
-  public void testSetAndGetMaxConnections() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getMaxConnections());
-    assertSame(builder, builder.setMaxConnections(1000));
-    assertEquals(1000, builder.getMaxConnections().intValue());
-    assertSame(builder, builder.setMaxConnections(null));
-    assertNull(builder.getMaxConnections());
-  }
+    ServerLauncher launcher = new Builder().build();
+    launcher.running.set(true);
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMaxConnectionsWithIllegalValue() {
-    try {
-      new Builder().setMaxConnections(-10);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Max Connections (-10) must be greater than 0!", expected.getMessage());
-      throw expected;
-    }
+    assertThat(launcher.isWaiting(cache)).isTrue();
   }
 
   @Test
-  public void testSetAndGetMaxMessageCount() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getMaxMessageCount());
-    assertSame(builder, builder.setMaxMessageCount(50));
-    assertEquals(50, builder.getMaxMessageCount().intValue());
-    assertSame(builder, builder.setMaxMessageCount(null));
-    assertNull(builder.getMaxMessageCount());
-  }
+  public void isWaitingReturnsFalseWhenSystemIsNotConnected() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    DistributedSystem system = mock(DistributedSystem.class, "DistributedSystem");
+    when(cache.getDistributedSystem()).thenReturn(system);
+    when(system.isConnected()).thenReturn(false);
+    when(cache.isReconnecting()).thenReturn(false);
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMaxMessageCountWithIllegalValue() {
-    try {
-      new Builder().setMaxMessageCount(0);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Max Message Count (0) must be greater than 0!", expected.getMessage());
-      throw expected;
-    }
-  }
+    ServerLauncher launcher = new Builder().setMemberName("serverOne").build();
+    launcher.running.set(true);
 
-  @Test
-  public void testSetAndGetMaxThreads() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getMaxThreads());
-    assertSame(builder, builder.setMaxThreads(16));
-    assertEquals(16, builder.getMaxThreads().intValue());
-    assertSame(builder, builder.setMaxThreads(null));
-    assertNull(builder.getMaxThreads());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMaxThreadsWithIllegalValue() {
-    try {
-      new Builder().setMaxThreads(-4);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Max Threads (-4) must be greater than 0!", expected.getMessage());
-      throw expected;
-    }
+    assertThat(launcher.isWaiting(cache)).isFalse();
   }
 
   @Test
-  public void testSetAndGetMessageTimeToLive() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getMessageTimeToLive());
-    assertSame(builder, builder.setMessageTimeToLive(30000));
-    assertEquals(30000, builder.getMessageTimeToLive().intValue());
-    assertSame(builder, builder.setMessageTimeToLive(null));
-    assertNull(builder.getMessageTimeToLive());
-  }
+  public void isWaitingReturnsFalseByDefault() throws Exception {
+    ServerLauncher launcher = new Builder().build();
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMessageTimeToLiveWithIllegalValue() {
-    try {
-      new Builder().setMessageTimeToLive(0);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("Message Time To Live (0) must be greater than 0!", expected.getMessage());
-      throw expected;
-    }
+    assertThat(launcher.isWaiting(null)).isFalse();
   }
 
   @Test
-  public void testSetAndGetSocketBufferSize() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getSocketBufferSize());
-    assertSame(builder, builder.setSocketBufferSize(32768));
-    assertEquals(32768, builder.getSocketBufferSize().intValue());
-    assertSame(builder, builder.setSocketBufferSize(null));
-    assertNull(builder.getSocketBufferSize());
-  }
+  public void isWaitingReturnsFalseWhenNotRunning() throws Exception {
+    ServerLauncher launcher = new Builder().build();
 
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetSocketBufferSizeWithIllegalValue() {
-    try {
-      new Builder().setSocketBufferSize(-8192);
-    } catch (IllegalArgumentException expected) {
-      assertEquals("The Server's Socket Buffer Size (-8192) must be greater than 0!",
-          expected.getMessage());
-      throw expected;
-    }
-  }
+    launcher.running.set(false);
 
-  @Test
-  public void testBuildWithMemberNameSetInApiPropertiesOnStart() {
-    ServerLauncher launcher =
-        new Builder().setCommand(ServerLauncher.Command.START).set(NAME, "serverABC").build();
-
-    assertNotNull(launcher);
-    assertEquals(ServerLauncher.Command.START, launcher.getCommand());
-    assertNull(launcher.getMemberName());
-    assertEquals("serverABC", launcher.getProperties().getProperty(NAME));
+    assertThat(launcher.isWaiting(null)).isFalse();
   }
 
   @Test
-  public void testBuildWithMemberNameSetInSystemPropertiesOnStart() {
-    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + NAME, "serverXYZ");
-
-    ServerLauncher launcher = new Builder().setCommand(ServerLauncher.Command.START).build();
+  public void isDisableDefaultServerReturnsFalseByDefault() throws Exception {
+    ServerLauncher launcher = new Builder().build();
 
-    assertNotNull(launcher);
-    assertEquals(ServerLauncher.Command.START, launcher.getCommand());
-    assertNull(launcher.getMemberName());
+    assertThat(launcher.isDisableDefaultServer()).isFalse();
   }
 
   @Test
-  public void testIsServing() {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final CacheServer mockCacheServer = mockContext.mock(CacheServer.class, "CacheServer");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.singletonList(mockCacheServer)));
-      }
-    });
-
-    final ServerLauncher serverLauncher = new Builder().setMemberName("serverOne").build();
-
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertTrue(serverLauncher.isServing(mockCache));
-  }
-
-  @Test
-  public void testIsServingWhenNoCacheServersExist() {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.emptyList()));
-      }
-    });
+  public void isDefaultServerEnabledForCacheReturnsTrueByDefault() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
 
-    final ServerLauncher serverLauncher = new Builder().setMemberName("serverOne").build();
+    ServerLauncher launcher = new Builder().build();
 
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertFalse(serverLauncher.isServing(mockCache));
+    assertThat(launcher.isDefaultServerEnabled(cache)).isTrue();
   }
 
   @Test
-  public void reconnectedCacheIsDiscovered() throws Exception {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final Cache mockReconnectedCache = mockContext.mock(Cache.class, "ReconnectedCache");
-
-    mockContext.checking(new Expectations() {
-      {
-        exactly(2).of(mockCache).isReconnecting();
-        will(returnValue(Boolean.FALSE));
-
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.emptyList()));
-
-        oneOf(mockCache).isReconnecting();
-        will(returnValue(Boolean.TRUE));
-
-        oneOf(mockCache).getReconnectedCache();
-        will(returnValue(mockReconnectedCache));
+  public void isDefaultServerEnabledForNullThrowsNullPointerException() throws Exception {
+    ServerLauncher launcher = new Builder().build();
 
-        oneOf(mockReconnectedCache).close();
-
-      }
-    });
-
-    final ServerLauncher serverLauncher =
-        new Builder().setMemberName("serverOne").setCache(mockCache).build();
-
-    assertNotNull(serverLauncher);
-    serverLauncher.waitOnServer();
+    assertThatThrownBy(() -> launcher.isDefaultServerEnabled(null))
+        .isInstanceOf(NullPointerException.class);
   }
 
   @Test
-  public void reconnectingDistributedSystemIsDisconnectedOnStop() throws Exception {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final DistributedSystem mockDistributedSystem =
-        mockContext.mock(DistributedSystem.class, "DistributedSystem");
-    final Cache mockReconnectedCache = mockContext.mock(Cache.class, "ReconnectedCache");
-
-    mockContext.checking(new Expectations() {
-      {
-        exactly(1).of(mockCache).isReconnecting();
-        will(returnValue(Boolean.TRUE));
-
-        exactly(1).of(mockCache).getReconnectedCache();
-        will(returnValue(mockReconnectedCache));
-
-        exactly(2).of(mockReconnectedCache).isReconnecting();
-        will(returnValue(Boolean.TRUE));
-
-        exactly(1).of(mockReconnectedCache).getReconnectedCache();
-        will(returnValue(null));
-
-        oneOf(mockReconnectedCache).getDistributedSystem();
-        will(returnValue(mockDistributedSystem));
+  public void isDefaultServerEnabledReturnsFalseWhenCacheServersExist() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    CacheServer cacheServer = mock(CacheServer.class, "CacheServer");
+    when(cache.getCacheServers()).thenReturn(Collections.singletonList(cacheServer));
 
-        oneOf(mockDistributedSystem).stopReconnecting();
+    ServerLauncher launcher = new Builder().build();
 
-        oneOf(mockReconnectedCache).close();
-      }
-    });
-
-    final ServerLauncher serverLauncher =
-        new Builder().setMemberName("serverOne").setCache(mockCache).build();
-
-    assertNotNull(serverLauncher);
-    serverLauncher.setIsRunningForTest();
-    serverLauncher.stop();
+    assertThat(launcher.isDefaultServerEnabled(cache)).isFalse();
   }
 
   @Test
-  public void testIsWaiting() {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final DistributedSystem mockDistributedSystem =
-        mockContext.mock(DistributedSystem.class, "DistributedSystem");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getDistributedSystem();
-        will(returnValue(mockDistributedSystem));
-        oneOf(mockDistributedSystem).isConnected();
-        will(returnValue(true));
-      }
-    });
-
-    final ServerLauncher serverLauncher = new Builder().setMemberName("serverOne").build();
+  public void isDisableDefaultServerReturnsTrueWhenDisabled() throws Exception {
+    ServerLauncher launcher = new Builder().setDisableDefaultServer(true).build();
 
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-
-    serverLauncher.running.set(true);
-
-    assertTrue(serverLauncher.isRunning());
-    assertTrue(serverLauncher.isWaiting(mockCache));
+    assertThat(launcher.isDisableDefaultServer()).isTrue();
   }
 
   @Test
-  public void testIsWaitingWhenNotConnected() {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final DistributedSystem mockDistributedSystem =
-        mockContext.mock(DistributedSystem.class, "DistributedSystem");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getDistributedSystem();
-        will(returnValue(mockDistributedSystem));
-        oneOf(mockDistributedSystem).isConnected();
-        will(returnValue(false));
-        oneOf(mockCache).isReconnecting();
-        will(returnValue(Boolean.FALSE));
-      }
-    });
-
-    final ServerLauncher serverLauncher = new Builder().setMemberName("serverOne").build();
-
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-
-    serverLauncher.running.set(true);
-
-    assertTrue(serverLauncher.isRunning());
-    assertFalse(serverLauncher.isWaiting(mockCache));
-  }
+  public void isDefaultServerEnabledReturnsFalseWhenDefaultServerDisabledIsTrueAndNoCacheServersExist()
+      throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    when(cache.getCacheServers()).thenReturn(Collections.emptyList());
 
-  @Test
-  public void testIsWaitingWhenNotRunning() {
-    ServerLauncher serverLauncher = new Builder().setMemberName("serverOne").build();
+    ServerLauncher launcher = new Builder().setDisableDefaultServer(true).build();
 
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-
-    serverLauncher.running.set(false);
-
-    assertFalse(serverLauncher.isRunning());
-    assertFalse(serverLauncher.isWaiting(null));
+    assertThat(launcher.isDefaultServerEnabled(cache)).isFalse();
   }
 
   @Test
-  public void testWaitOnServer() throws Throwable {
-    TestFramework.runOnce(new ServerWaitMultiThreadedTestCase());
-  }
+  public void isDefaultServerEnabledReturnsFalseWhenDefaultServerDisabledIsTrueAndCacheServersExist()
+      throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    CacheServer cacheServer = mock(CacheServer.class, "CacheServer");
+    when(cache.getCacheServers()).thenReturn(Collections.singletonList(cacheServer));
 
-  @Test
-  public void testIsDefaultServerEnabled() {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.emptyList()));
-      }
-    });
-
-    ServerLauncher serverLauncher = new Builder().setMemberName("serverOne").build();
-
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertFalse(serverLauncher.isDisableDefaultServer());
-    assertTrue(serverLauncher.isDefaultServerEnabled(mockCache));
-  }
+    ServerLauncher launcher = new Builder().setDisableDefaultServer(true).build();
 
-  @Test
-  public void testIsDefaultServerEnabledWhenCacheServersExist() {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final CacheServer mockCacheServer = mockContext.mock(CacheServer.class, "CacheServer");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.singletonList(mockCacheServer)));
-      }
-    });
-
-    final ServerLauncher serverLauncher =
-        new Builder().setMemberName("serverOne").setDisableDefaultServer(false).build();
-
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertFalse(serverLauncher.isDisableDefaultServer());
-    assertFalse(serverLauncher.isDefaultServerEnabled(mockCache));
+    assertThat(launcher.isDefaultServerEnabled(cache)).isFalse();
   }
 
   @Test
-  public void testIsDefaultServerEnabledWhenNoCacheServersExistAndDefaultServerDisabled() {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.emptyList()));
-      }
-    });
-
-    final ServerLauncher serverLauncher =
-        new Builder().setMemberName("serverOne").setDisableDefaultServer(true).build();
-
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertTrue(serverLauncher.isDisableDefaultServer());
-    assertFalse(serverLauncher.isDefaultServerEnabled(mockCache));
-  }
+  public void startCacheServerStartsCacheServerWithBuilderValues() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    CacheServer cacheServer = mock(CacheServer.class, "CacheServer");
+    when(cache.getCacheServers()).thenReturn(Collections.emptyList());
+    when(cache.addCacheServer()).thenReturn(cacheServer);
+    ServerLauncher launcher = new Builder().setServerBindAddress(null).setServerPort(11235).build();
 
-  @Test
-  public void testStartCacheServer() throws IOException {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final CacheServer mockCacheServer = mockContext.mock(CacheServer.class, "CacheServer");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.emptyList()));
-        oneOf(mockCache).addCacheServer();
-        will(returnValue(mockCacheServer));
-        oneOf(mockCacheServer).setBindAddress(with(aNull(String.class)));
-        oneOf(mockCacheServer).setPort(with(equal(11235)));
-        oneOf(mockCacheServer).start();
-      }
-    });
-
-    final ServerLauncher serverLauncher = new Builder().setMemberName("serverOne")
-        .setServerBindAddress(null).setServerPort(11235).setDisableDefaultServer(false).build();
-
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertFalse(serverLauncher.isDisableDefaultServer());
-
-    serverLauncher.startCacheServer(mockCache);
-  }
+    launcher.startCacheServer(cache);
 
-  @Test
-  public void testStartCacheServerWhenDefaultServerDisabled() throws IOException {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.emptyList()));
-      }
-    });
-
-    final ServerLauncher serverLauncher =
-        new Builder().setMemberName("serverOne").setDisableDefaultServer(true).build();
-
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertTrue(serverLauncher.isDisableDefaultServer());
-
-    serverLauncher.startCacheServer(mockCache);
+    verify(cacheServer, times(1)).setBindAddress(isNull());
+    verify(cacheServer, times(1)).setPort(eq(11235));
+    verify(cacheServer, times(1)).start();
   }
 
   @Test
-  public void testStartCacheServerWithExistingCacheServer() throws IOException {
-    final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-    final CacheServer mockCacheServer = mockContext.mock(CacheServer.class, "CacheServer");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockCache).getCacheServers();
-        will(returnValue(Collections.singletonList(mockCacheServer)));
-      }
-    });
+  public void startCacheServerDoesNothingWhenDefaultServerDisabled() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    CacheServer cacheServer = mock(CacheServer.class, "CacheServer");
+    when(cache.getCacheServers()).thenReturn(Collections.emptyList());
+    when(cache.addCacheServer()).thenReturn(cacheServer);
+    ServerLauncher launcher = new Builder().setDisableDefaultServer(true).build();
 
-    final ServerLauncher serverLauncher =
-        new Builder().setMemberName("serverOne").setDisableDefaultServer(false).build();
+    launcher.startCacheServer(cache);
 
-    assertNotNull(serverLauncher);
-    assertEquals("serverOne", serverLauncher.getMemberName());
-    assertFalse(serverLauncher.isDisableDefaultServer());
-
-    serverLauncher.startCacheServer(mockCache);
+    verify(cacheServer, times(0)).setBindAddress(anyString());
+    verify(cacheServer, times(0)).setPort(anyInt());
+    verify(cacheServer, times(0)).start();
   }
 
-  private class ServerWaitMultiThreadedTestCase extends MultithreadedTestCase {
-
-    private final AtomicBoolean connectionStateHolder = new AtomicBoolean(true);
-
-    private ServerLauncher serverLauncher;
-
-    @Override
-    public void initialize() {
-      super.initialize();
-
-      final Cache mockCache = mockContext.mock(Cache.class, "Cache");
-
-      final DistributedSystem mockDistributedSystem = new DistributedSystemAdapter() {
-        @Override
-        public boolean isConnected() {
-          return connectionStateHolder.get();
-        }
-      };
-
-      mockContext.checking(new Expectations() {
-        {
-          allowing(mockCache).getDistributedSystem();
-          will(returnValue(mockDistributedSystem));
-          allowing(mockCache).isReconnecting();
-          will(returnValue(Boolean.FALSE));
-          allowing(mockCache).getCacheServers();
-          will(returnValue(Collections.emptyList()));
-          oneOf(mockCache).close();
-        }
-      });
-
-      this.serverLauncher = new Builder().setMemberName("dataMember").setDisableDefaultServer(true)
-          .setCache(mockCache).build();
-
-      assertNotNull(this.serverLauncher);
-      assertEquals("dataMember", this.serverLauncher.getMemberName());
-      assertTrue(this.serverLauncher.isDisableDefaultServer());
-      assertTrue(connectionStateHolder.get());
-    }
-
-    public void thread1() {
-      assertTick(0);
-
-      Thread.currentThread().setName("GemFire Data Member 'main' Thread");
-      this.serverLauncher.running.set(true);
-
-      assertTrue(this.serverLauncher.isRunning());
-      assertFalse(this.serverLauncher.isServing(this.serverLauncher.getCache()));
-      assertTrue(this.serverLauncher.isWaiting(this.serverLauncher.getCache()));
-
-      this.serverLauncher.waitOnServer();
-
-      assertTick(1); // NOTE the tick does not advance when the other Thread terminates
-    }
-
-    public void thread2() {
-      waitForTick(1);
-
-      Thread.currentThread().setName("GemFire 'shutdown' Thread");
-
-      assertTrue(this.serverLauncher.isRunning());
+  @Test
+  public void startCacheServerDoesNothingWhenCacheServerAlreadyExists() throws Exception {
+    Cache cache = mock(Cache.class, "Cache");
+    CacheServer cacheServer1 = mock(CacheServer.class, "CacheServer1");
+    CacheServer cacheServer2 = mock(CacheServer.class, "CacheServer2");
+    when(cache.getCacheServers()).thenReturn(Collections.singletonList(cacheServer1));
+    when(cache.addCacheServer()).thenReturn(cacheServer1);
+    ServerLauncher launcher = new Builder().build();
 
-      this.connectionStateHolder.set(false);
-    }
+    launcher.startCacheServer(cache);
 
-    @Override
-    public void finish() {
-      super.finish();
-      assertFalse(this.serverLauncher.isRunning());
-    }
+    verify(cacheServer2, times(0)).setBindAddress(anyString());
+    verify(cacheServer2, times(0)).setPort(anyInt());
+    verify(cacheServer2, times(0)).start();
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWaitOnServerMultiThreadedTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWaitOnServerMultiThreadedTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWaitOnServerMultiThreadedTest.java
new file mode 100644
index 0000000..5aaecb9
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWaitOnServerMultiThreadedTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Collections;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import edu.umd.cs.mtc.MultithreadedTestCase;
+import edu.umd.cs.mtc.TestFramework;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Multithreaded unit tests for {@link ServerLauncher}. Extracted from {@link ServerLauncherTest}.
+ */
+@Category(UnitTest.class)
+public class ServerLauncherWaitOnServerMultiThreadedTest {
+
+  private final AtomicBoolean connectionStateHolder = new AtomicBoolean(true);
+
+  private Cache cache;
+  private ServerLauncher serverLauncher;
+
+  @Before
+  public void setUp() throws Exception {
+    DistributedSystem system = mock(DistributedSystem.class, "DistributedSystem");
+    when(system.isConnected()).thenAnswer(invocation -> connectionStateHolder.get());
+
+    cache = mock(Cache.class, "Cache");
+    when(cache.getDistributedSystem()).thenReturn(system);
+    when(cache.isReconnecting()).thenReturn(false);
+    when(cache.getCacheServers()).thenReturn(Collections.emptyList());
+  }
+
+  @Test
+  public void waitOnServer() throws Exception {
+    runTest(new ServerWaitMultiThreadedTestCase());
+  }
+
+  private static void runTest(final MultithreadedTestCase test) {
+    try {
+      TestFramework.runOnce(test);
+    } catch (Throwable t) {
+      throw new AssertionError(t);
+    }
+  }
+
+  /**
+   * Implementation of MultithreadedTestCase.
+   */
+  private class ServerWaitMultiThreadedTestCase extends MultithreadedTestCase {
+
+    @Override
+    public void initialize() {
+      serverLauncher = new ServerLauncher.Builder().setMemberName("dataMember")
+          .setDisableDefaultServer(true).setCache(cache).build();
+
+      assertThat(connectionStateHolder.get()).isTrue();
+    }
+
+    public void thread1() {
+      assertTick(0);
+
+      Thread.currentThread().setName("GemFire Data Member 'main' Thread");
+      serverLauncher.running.set(true);
+
+      assertThat(serverLauncher.isRunning()).isTrue();
+      assertThat(serverLauncher.isServing(serverLauncher.getCache())).isFalse();
+      assertThat(serverLauncher.isWaiting(serverLauncher.getCache())).isTrue();
+
+      serverLauncher.waitOnServer();
+
+      assertTick(1); // NOTE the tick does not advance when the other Thread terminates
+    }
+
+    public void thread2() {
+      waitForTick(1);
+
+      Thread.currentThread().setName("GemFire 'shutdown' Thread");
+
+      assertThat(serverLauncher.isRunning()).isTrue();
+
+      connectionStateHolder.set(false);
+    }
+
+    @Override
+    public void finish() {
+      assertThat(serverLauncher.isRunning()).isFalse();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderIntegrationTest.java
deleted file mode 100644
index 6fd57c7..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderIntegrationTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import org.apache.geode.cache.Cache;
-import org.apache.geode.distributed.AbstractLauncher.Status;
-import org.apache.geode.distributed.ServerLauncher.Builder;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.mockito.Mockito;
-
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.junit.Assert.*;
-
-/**
- * Extracted from ServerLauncherLocalIntegrationTest.
- */
-@Category(IntegrationTest.class)
-public class ServerLauncherWithProviderIntegrationTest
-    extends AbstractServerLauncherIntegrationTestCase {
-
-  @Before
-  public final void setUpServerLauncherWithSpringTest() throws Exception {
-    disconnectFromDS();
-    System.setProperty(ProcessType.TEST_PREFIX_PROPERTY, getUniqueName() + "-");
-  }
-
-  @After
-  public final void tearDownServerLauncherWithSpringTest() throws Exception {
-    MockServerLauncherCacheProvider.setCache(null);
-    disconnectFromDS();
-
-  }
-
-  // NOTE make sure bugs like Trac #51201 never happen again!!!
-  @Test
-  public void testBootstrapGemFireServerWithProvider() throws Throwable {
-    Cache mockCache = Mockito.mock(Cache.class);
-    MockServerLauncherCacheProvider.setCache(mockCache);
-    this.launcher =
-        new Builder().setDisableDefaultServer(true).setForce(true).setMemberName(getUniqueName())
-            .setSpringXmlLocation("spring/spring-gemfire-context.xml").set(MCAST_PORT, "0").build();
-
-    assertNotNull(this.launcher);
-
-    try {
-      assertEquals(Status.ONLINE, this.launcher.start().getStatus());
-
-      waitForServerToStart(this.launcher);
-
-      Cache cache = this.launcher.getCache();
-
-      assertEquals(mockCache, cache);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      assertNull(this.launcher.getCache());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderRegressionTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderRegressionTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderRegressionTest.java
new file mode 100644
index 0000000..30dd081
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherWithProviderRegressionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static org.apache.geode.internal.process.ProcessType.PROPERTY_TEST_PREFIX;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Extracted from {@link ServerLauncherLocalIntegrationTest}. This tests the same mechanism used by
+ * Spring Data GemFire/Geode. This test confirms the fix for TRAC #51201 (see below).
+ *
+ * <p>
+ * TRAC #51201: ServerLauncher.start fails to configure server with Spring
+ */
+@Category(IntegrationTest.class)
+public class ServerLauncherWithProviderRegressionTest extends ServerLauncherIntegrationTestCase {
+
+  private Cache providerCache;
+
+  @Before
+  public void setUp() throws Exception {
+    disconnectFromDS();
+    System.setProperty(PROPERTY_TEST_PREFIX, getUniqueName() + "-");
+
+    providerCache = mock(Cache.class);
+    TestServerLauncherCacheProvider.setCache(providerCache);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    TestServerLauncherCacheProvider.setCache(null);
+    disconnectFromDS();
+  }
+
+  @Test
+  public void startGetsCacheFromServerLauncherCacheProvider() throws Exception {
+    startServer(newBuilder().setDisableDefaultServer(true).setSpringXmlLocation(springXml()));
+
+    Cache cache = launcher.getCache();
+
+    assertThat(cache).isEqualTo(providerCache);
+  }
+
+  private String springXml() {
+    return "spring/spring-gemfire-context.xml";
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/TestServerLauncherCacheProvider.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/TestServerLauncherCacheProvider.java b/geode-core/src/test/java/org/apache/geode/distributed/TestServerLauncherCacheProvider.java
new file mode 100644
index 0000000..d71a7c0
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/TestServerLauncherCacheProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import java.util.Properties;
+
+import org.apache.geode.cache.Cache;
+
+/**
+ * Implementation of {@link ServerLauncherCacheProvider} used by
+ * {@link ServerLauncherWithProviderRegressionTest}.
+ */
+public class TestServerLauncherCacheProvider implements ServerLauncherCacheProvider {
+
+  private static Cache cache;
+
+  public static Cache getCache() {
+    return cache;
+  }
+
+  public static void setCache(final Cache cache) {
+    TestServerLauncherCacheProvider.cache = cache;
+  }
+
+  @Override
+  public Cache createCache(final Properties gemfireProperties,
+      final ServerLauncher serverLauncher) {
+    return cache;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/UsesLocatorCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/UsesLocatorCommand.java b/geode-core/src/test/java/org/apache/geode/distributed/UsesLocatorCommand.java
new file mode 100644
index 0000000..983a7a3
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/UsesLocatorCommand.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import java.util.List;
+
+public interface UsesLocatorCommand {
+
+  String getJavaPath();
+
+  List<String> getJvmArguments();
+
+  String getClassPath();
+
+  String getName();
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/UsesServerCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/UsesServerCommand.java b/geode-core/src/test/java/org/apache/geode/distributed/UsesServerCommand.java
new file mode 100644
index 0000000..6ac7f8e
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/UsesServerCommand.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import java.util.List;
+
+public interface UsesServerCommand {
+
+  String getJavaPath();
+
+  List<String> getJvmArguments();
+
+  String getClassPath();
+
+  String getName();
+
+  boolean getDisableDefaultServer();
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/support/DistributedSystemAdapter.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/support/DistributedSystemAdapter.java b/geode-core/src/test/java/org/apache/geode/distributed/support/DistributedSystemAdapter.java
deleted file mode 100644
index b2b990e..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/support/DistributedSystemAdapter.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed.support;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.net.InetAddress;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.geode.CancelCriterion;
-import org.apache.geode.LogWriter;
-import org.apache.geode.StatisticDescriptor;
-import org.apache.geode.Statistics;
-import org.apache.geode.StatisticsType;
-import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.distributed.DistributedSystem;
-
-/**
- * The DistributedSystemAdapter class is an adapter extending DistributedSystem to provide default
- * behavior for the abstract methods when testing.
- * <p/>
- * 
- * @see org.apache.geode.distributed.DistributedSystem
- * @since GemFire 8.0
- */
-@SuppressWarnings("unused")
-public abstract class DistributedSystemAdapter extends DistributedSystem {
-
-  @Override
-  public LogWriter getLogWriter() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public LogWriter getSecurityLogWriter() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Properties getProperties() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Properties getSecurityProperties() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public CancelCriterion getCancelCriterion() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public void disconnect() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public boolean isConnected() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public boolean isReconnecting() {
-    return false;
-  }
-
-  public boolean waitUntilReconnected(long time, TimeUnit units) throws InterruptedException {
-    return false;
-  }
-
-  @Override
-  public void stopReconnecting() {}
-
-  @Override
-  public DistributedSystem getReconnectedSystem() {
-    return null;
-  }
-
-  @Override
-  public long getId() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public String getMemberId() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public DistributedMember getDistributedMember() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Set<DistributedMember> getAllOtherMembers() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Set<DistributedMember> getGroupMembers(final String group) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public String getName() {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics createStatistics(final StatisticsType type) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics createStatistics(final StatisticsType type, final String textId) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics createStatistics(final StatisticsType type, final String textId,
-      final long numericId) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics createAtomicStatistics(final StatisticsType type) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics createAtomicStatistics(final StatisticsType type, final String textId) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics createAtomicStatistics(final StatisticsType type, final String textId,
-      final long numericId) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics[] findStatisticsByType(final StatisticsType type) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics[] findStatisticsByTextId(final String textId) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Statistics[] findStatisticsByNumericId(final long numericId) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createIntCounter(final String name, final String description,
-      final String units) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createLongCounter(final String name, final String description,
-      final String units) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createDoubleCounter(final String name, final String description,
-      final String units) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createIntGauge(final String name, final String description,
-      final String units) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createLongGauge(final String name, final String description,
-      final String units) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createDoubleGauge(final String name, final String description,
-      final String units) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createIntCounter(final String name, final String description,
-      final String units, final boolean largerBetter) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createLongCounter(final String name, final String description,
-      final String units, final boolean largerBetter) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createDoubleCounter(final String name, final String description,
-      final String units, final boolean largerBetter) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createIntGauge(final String name, final String description,
-      final String units, final boolean largerBetter) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createLongGauge(final String name, final String description,
-      final String units, final boolean largerBetter) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticDescriptor createDoubleGauge(final String name, final String description,
-      final String units, final boolean largerBetter) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticsType createType(final String name, final String description,
-      final StatisticDescriptor[] stats) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticsType findType(final String name) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public StatisticsType[] createTypesFromXml(final Reader reader) throws IOException {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public Set<DistributedMember> findDistributedMembers(InetAddress address) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-  @Override
-  public DistributedMember findDistributedMember(String name) {
-    throw new UnsupportedOperationException("Not Implemented!");
-  }
-
-
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/AbstractProcessStreamReaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/AbstractProcessStreamReaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/AbstractProcessStreamReaderIntegrationTest.java
new file mode 100755
index 0000000..18feea7
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/AbstractProcessStreamReaderIntegrationTest.java
@@ -0,0 +1,309 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR;
+import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionFactory;
+import org.junit.After;
+import org.junit.Before;
+
+import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
+import org.apache.geode.internal.util.StopWatch;
+
+/**
+ * Abstract base class for functional integration testing of {@link ProcessStreamReader}.
+ */
+public abstract class AbstractProcessStreamReaderIntegrationTest {
+
+  /** Timeout to join to a running ProcessStreamReader thread */
+  private static final int READER_JOIN_TIMEOUT_MILLIS = 20 * 1000;
+
+  /** Sleep timeout for {@link ProcessSleeps} instead of sleeping Long.MAX_VALUE */
+  private static final int PROCESS_FAIL_SAFE_TIMEOUT_MILLIS = 10 * 60 * 1000;
+
+  /** Additional time for launched processes to live before terminating */
+  private static final int PROCESS_TIME_TO_LIVE_MILLIS = 3 * 500;
+
+  /** Timeout to wait for a new {@link ProcessStreamReader} to be running */
+  private static final int WAIT_FOR_READER_IS_RUNNING_TIMEOUT_MILLIS = 20 * 1000;
+
+  protected Process process;
+  protected ProcessStreamReader stderr;
+  protected ProcessStreamReader stdout;
+
+  private StringBuffer stdoutBuffer;
+  private StringBuffer stderrBuffer;
+
+  @Before
+  public void setUpAbstractProcessStreamReaderIntegrationTest() {
+    stdoutBuffer = new StringBuffer();
+    stderrBuffer = new StringBuffer();
+  }
+
+  @After
+  public void afterProcessStreamReaderTestCase() throws Exception {
+    if (stderr != null) {
+      stderr.stop();
+    }
+    if (stdout != null) {
+      stdout.stop();
+    }
+    if (process != null) {
+      try {
+        process.getErrorStream().close();
+        process.getInputStream().close();
+        process.getOutputStream().close();
+      } finally {
+        // this is async and can require more than 10 seconds on slower machines
+        process.destroy();
+      }
+    }
+  }
+
+  protected abstract ReadingMode getReadingMode();
+
+  protected void assertThatProcessAndReadersStopped() throws InterruptedException {
+    assertThatProcessAndReadersStoppedWithExitValue(0);
+  }
+
+  protected void assertThatProcessAndReadersStoppedWithExitValue(final int exitValue)
+      throws InterruptedException {
+    assertThat(process.exitValue()).isEqualTo(exitValue);
+    assertThat(stdout.join(READER_JOIN_TIMEOUT_MILLIS).isRunning()).isFalse();
+    assertThat(stderr.join(READER_JOIN_TIMEOUT_MILLIS).isRunning()).isFalse();
+  }
+
+  protected void assertThatProcessAndReadersDied() throws InterruptedException {
+    assertThat(process.exitValue()).isGreaterThan(0);
+    assertThat(stdout.join(READER_JOIN_TIMEOUT_MILLIS).isRunning()).isFalse();
+    assertThat(stderr.join(READER_JOIN_TIMEOUT_MILLIS).isRunning()).isFalse();
+  }
+
+  protected void assertThatProcessIsAlive(final Process process) {
+    assertThat(process.isAlive()).isTrue();
+  }
+
+  protected void assertThatStdErrContains(final String value) {
+    assertThat(stderrBuffer.toString()).contains(value);
+  }
+
+  protected void assertThatStdErrContainsExactly(final String value) {
+    assertThat(stderrBuffer.toString()).isEqualTo(value);
+  }
+
+  protected void assertThatStdOutContainsExactly(final String value) {
+    assertThat(stdoutBuffer.toString()).isEqualTo(value);
+  }
+
+  protected void givenRunningProcessWithStreamReaders(final Class<?> mainClass) {
+    givenStartedProcess(mainClass);
+
+    assertThat(process.isAlive()).isTrue();
+
+    await().until(() -> assertThat(stdout.isRunning()).isTrue());
+    await().until(() -> assertThat(stderr.isRunning()).isTrue());
+  }
+
+  private void givenStartedProcess(final Class<?> mainClass) {
+    try {
+      process = new ProcessBuilder(createCommandLine(mainClass)).start();
+      stdout = buildProcessStreamReader(process.getInputStream(), getReadingMode());
+      stderr = buildProcessStreamReader(process.getErrorStream(), getReadingMode());
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected void givenStartedProcessWithStreamListeners(final Class<?> mainClass) {
+    try {
+      process = new ProcessBuilder(createCommandLine(mainClass)).start();
+      stdout = buildProcessStreamReader(process.getInputStream(), getReadingMode(), stdoutBuffer);
+      stderr = buildProcessStreamReader(process.getErrorStream(), getReadingMode(), stderrBuffer);
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected ConditionFactory await() {
+    return Awaitility.await().atMost(WAIT_FOR_READER_IS_RUNNING_TIMEOUT_MILLIS, MILLISECONDS);
+  }
+
+  protected static String[] createCommandLine(final Class<?> clazz) {
+    List<String> commandLine = new ArrayList<>();
+
+    commandLine.add(getJavaPath());
+    commandLine.add("-server");
+    commandLine.add("-classpath");
+    commandLine.add(getClassPath());
+    commandLine.add("-D" + "java.awt.headless=true");
+    commandLine.add(clazz.getName());
+
+    return commandLine.toArray(new String[commandLine.size()]);
+  }
+
+  protected void waitUntilProcessStops() {
+    await().until(() -> assertThat(isProcessAlive(process)).isFalse());
+  }
+
+  private ProcessStreamReader buildProcessStreamReader(final InputStream stream,
+      final ReadingMode mode) {
+    return new ProcessStreamReader.Builder(process).inputStream(stream).readingMode(mode).build()
+        .start();
+  }
+
+  private ProcessStreamReader buildProcessStreamReader(final InputStream stream,
+      final ReadingMode mode, final StringBuffer buffer) {
+    ProcessStreamReader.Builder builder =
+        new ProcessStreamReader.Builder(process).inputStream(stream).readingMode(mode);
+    if (buffer != null) {
+      builder.inputListener(buffer::append);
+    }
+    return builder.build().start();
+  }
+
+  private static String getClassPath() {
+    return System.getProperty("java.class.path");
+  }
+
+  private static String getJavaPath() {
+    String java = "java";
+    return new File(new File(System.getProperty("java.home"), "bin"), java).getPath();
+  }
+
+  private static void sleepAtMost(final int duration) throws InterruptedException {
+    StopWatch stopWatch = new StopWatch(true);
+    while (stopWatch.elapsedTimeMillis() < duration) {
+      Thread.sleep(1000);
+    }
+  }
+
+  /**
+   * Class with main that sleeps until destroyed.
+   */
+  protected static class ProcessSleeps {
+    public static void main(final String... args) throws InterruptedException {
+      sleepAtMost(PROCESS_FAIL_SAFE_TIMEOUT_MILLIS);
+    }
+  }
+
+  /**
+   * Class with main that throws Error.
+   */
+  protected static class ProcessThrowsError {
+    private static final String[] LINES =
+        new String[] {"ProcessThrowsError is starting" + LINE_SEPARATOR,
+            "ProcessThrowsError is sleeping" + LINE_SEPARATOR,
+            "ProcessThrowsError is throwing" + LINE_SEPARATOR};
+
+    protected static final String STDOUT = "";
+
+    protected static final String ERROR_MSG = "ProcessThrowsError throws Error";
+
+    public static void main(final String... args) throws InterruptedException {
+      System.err.print(LINES[0]);
+      System.err.print(LINES[1]);
+      sleepAtMost(PROCESS_TIME_TO_LIVE_MILLIS);
+      System.err.print(LINES[2]);
+      throw new Error(ERROR_MSG);
+    }
+  }
+
+  /**
+   * Class with main that prints to stdout and sleeps.
+   */
+  protected static class ProcessPrintsToStdout {
+    private static final String[] LINES =
+        new String[] {"ProcessPrintsToStdout is starting" + LINE_SEPARATOR,
+            "ProcessPrintsToStdout is sleeping" + LINE_SEPARATOR,
+            "ProcessPrintsToStdout is exiting" + LINE_SEPARATOR};
+
+    protected static final String STDOUT =
+        new StringBuilder().append(LINES[0]).append(LINES[1]).append(LINES[2]).toString();
+
+    protected static final String STDERR = "";
+
+    public static void main(final String... args) throws InterruptedException {
+      System.out.print(LINES[0]);
+      System.out.print(LINES[1]);
+      sleepAtMost(PROCESS_TIME_TO_LIVE_MILLIS);
+      System.out.print(LINES[2]);
+    }
+  }
+
+  /**
+   * Class with main that prints to stderr and sleeps.
+   */
+  protected static class ProcessPrintsToStderr {
+    private static final String[] LINES =
+        new String[] {"ProcessPrintsToStdout is starting" + LINE_SEPARATOR,
+            "ProcessPrintsToStdout is sleeping" + LINE_SEPARATOR,
+            "ProcessPrintsToStdout is exiting" + LINE_SEPARATOR};
+
+    protected static final String STDOUT = "";
+
+    protected static final String STDERR =
+        new StringBuilder().append(LINES[0]).append(LINES[1]).append(LINES[2]).toString();
+
+    public static void main(final String... args) throws InterruptedException {
+      System.err.print(LINES[0]);
+      System.err.print(LINES[1]);
+      sleepAtMost(PROCESS_TIME_TO_LIVE_MILLIS);
+      System.err.print(LINES[2]);
+    }
+  }
+
+  /**
+   * Class with main that prints to both stdout and stderr and sleeps.
+   */
+  protected static class ProcessPrintsToBoth {
+    private static final String[] OUT_LINES =
+        new String[] {"ProcessPrintsToBoth(out) is starting" + LINE_SEPARATOR,
+            "ProcessPrintsToBoth(out) is sleeping" + LINE_SEPARATOR,
+            "ProcessPrintsToBoth(out) is exiting" + LINE_SEPARATOR};
+
+    private static final String[] ERR_LINES =
+        new String[] {"ProcessPrintsToBoth(err) is starting" + LINE_SEPARATOR,
+            "ProcessPrintsToBoth(err) is sleeping" + LINE_SEPARATOR,
+            "ProcessPrintsToBoth(err) is exiting" + LINE_SEPARATOR};
+
+    protected static final String STDOUT = new StringBuilder().append(OUT_LINES[0])
+        .append(OUT_LINES[1]).append(OUT_LINES[2]).toString();
+
+    protected static final String STDERR = new StringBuilder().append(ERR_LINES[0])
+        .append(ERR_LINES[1]).append(ERR_LINES[2]).toString();
+
+    public static void main(final String... args) throws InterruptedException {
+      System.out.print(OUT_LINES[0]);
+      System.err.print(ERR_LINES[0]);
+      System.out.print(OUT_LINES[1]);
+      System.err.print(ERR_LINES[1]);
+      sleepAtMost(PROCESS_TIME_TO_LIVE_MILLIS);
+      System.out.print(OUT_LINES[2]);
+      System.err.print(ERR_LINES[2]);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/AttachProcessUtilsTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/AttachProcessUtilsTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/AttachProcessUtilsTest.java
new file mode 100644
index 0000000..f167f60
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/AttachProcessUtilsTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.lang.AvailablePid;
+import org.apache.geode.test.junit.Retry;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.apache.geode.test.junit.rules.RetryRule;
+
+/**
+ * Unit tests for {@link AttachProcessUtils}.
+ *
+ * <p>
+ * Tests involving fakePid use {@link RetryRule} because the fakePid may become used by a real
+ * process before the test executes.
+ */
+@Category(UnitTest.class)
+public class AttachProcessUtilsTest {
+
+  private static final int PREFERRED_FAKE_PID = 42;
+
+  private int actualPid;
+  private int fakePid;
+  private AttachProcessUtils attachProcessUtils;
+
+  @Rule
+  public RetryRule retryRule = new RetryRule();
+
+  @Before
+  public void before() throws Exception {
+    actualPid = identifyPid();
+    fakePid = new AvailablePid().findAvailablePid(PREFERRED_FAKE_PID);
+    attachProcessUtils = new AttachProcessUtils();
+  }
+
+  @Test
+  public void isAttachApiAvailable_returnsTrue() throws Exception {
+    assertThat(attachProcessUtils.isAttachApiAvailable()).isTrue();
+  }
+
+  @Test
+  public void isAvailable_returnsTrue() throws Exception {
+    assertThat(attachProcessUtils.isAvailable()).isTrue();
+  }
+
+  @Test
+  public void isProcessAlive_withLivePid_returnsTrue() throws Exception {
+    assertThat(attachProcessUtils.isProcessAlive(actualPid)).isTrue();
+  }
+
+  @Test
+  @Retry(3)
+  public void isProcessAlive_withDeadPid_returnsFalse() throws Exception {
+    assertThat(attachProcessUtils.isProcessAlive(fakePid)).isFalse();
+  }
+
+  @Test
+  @Retry(3)
+  public void killProcess_throwsUnsupportedOperationException() throws Exception {
+    assertThatThrownBy(() -> attachProcessUtils.killProcess(fakePid))
+        .isInstanceOf(UnsupportedOperationException.class)
+        .hasMessage("killProcess(int) not supported by AttachProcessUtils");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/BaseProcessStreamReaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/BaseProcessStreamReaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/BaseProcessStreamReaderIntegrationTest.java
new file mode 100644
index 0000000..1aa93bb
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/BaseProcessStreamReaderIntegrationTest.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import org.junit.Test;
+
+/**
+ * Integration tests that should be executed under both {@link ProcessStreamReader.ReadingMode}s.
+ */
+public abstract class BaseProcessStreamReaderIntegrationTest
+    extends AbstractProcessStreamReaderIntegrationTest {
+
+  @Test
+  public void processLivesAfterClosingStreams() throws Exception {
+    // arrange
+    givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+    // act
+    process.getErrorStream().close();
+    process.getOutputStream().close();
+    process.getInputStream().close();
+
+    // assert
+    assertThatProcessIsAlive(process);
+  }
+
+  @Test
+  public void processTerminatesWhenDestroyed() throws Exception {
+    // arrange
+    givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+    // act
+    process.destroy(); // results in SIGTERM which usually has an exit code of 143
+
+    // assert
+    waitUntilProcessStops();
+    assertThatProcessAndReadersDied();
+  }
+}


[21/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
index 158e7bf..ae64691 100755
--- a/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/ServerLauncher.java
@@ -12,12 +12,45 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.distributed;
 
+import static org.apache.commons.lang.StringUtils.EMPTY;
+import static org.apache.commons.lang.StringUtils.defaultIfBlank;
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang.StringUtils.lowerCase;
 import static org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.apache.geode.distributed.ConfigurationProperties.SERVER_BIND_ADDRESS;
+import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
+import static org.apache.geode.internal.lang.StringUtils.wrap;
+import static org.apache.geode.internal.lang.SystemUtils.CURRENT_DIRECTORY;
+import static org.apache.geode.internal.util.IOUtils.tryGetCanonicalPathElseGetAbsolutePath;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ServiceLoader;
+import java.util.TreeMap;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import joptsimple.OptionException;
+import joptsimple.OptionParser;
+import joptsimple.OptionSet;
 
 import org.apache.geode.SystemFailure;
 import org.apache.geode.cache.Cache;
@@ -36,10 +69,7 @@ import org.apache.geode.internal.cache.PartitionedRegion;
 import org.apache.geode.internal.cache.tier.sockets.CacheServerHelper;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.lang.ObjectUtils;
-import org.apache.geode.internal.lang.StringUtils;
-import org.apache.geode.internal.lang.SystemUtils;
 import org.apache.geode.internal.net.SocketCreator;
-import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.process.ConnectionFailedException;
 import org.apache.geode.internal.process.ControlNotificationHandler;
 import org.apache.geode.internal.process.ControllableProcess;
@@ -53,7 +83,6 @@ import org.apache.geode.internal.process.ProcessLauncherContext;
 import org.apache.geode.internal.process.ProcessType;
 import org.apache.geode.internal.process.StartupStatusListener;
 import org.apache.geode.internal.process.UnableToControlProcessException;
-import org.apache.geode.internal.util.IOUtils;
 import org.apache.geode.lang.AttachAPINotFoundException;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.json.GfJsonArray;
@@ -63,30 +92,6 @@ import org.apache.geode.pdx.PdxSerializer;
 import org.apache.geode.security.AuthenticationRequiredException;
 import org.apache.geode.security.GemFireSecurityException;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.ServiceLoader;
-import java.util.TreeMap;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-import joptsimple.OptionException;
-import joptsimple.OptionParser;
-import joptsimple.OptionSet;
-
 /**
  * The ServerLauncher class is a launcher class with main method to start a GemFire Server (implying
  * a GemFire Cache Server process).
@@ -114,6 +119,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
     helpMap.put("assign-buckets",
         LocalizedStrings.ServerLauncher_SERVER_ASSIGN_BUCKETS_HELP.toLocalizedString());
     helpMap.put("debug", LocalizedStrings.ServerLauncher_SERVER_DEBUG_HELP.toLocalizedString());
+    helpMap.put("delete-pid-file-on-stop",
+        "Specifies that this Server's PID file should be deleted on stop.  The default is to not delete this Server's PID file until JVM exit if --delete-pid-file-on-stop is not specified.");
     helpMap.put("dir", LocalizedStrings.ServerLauncher_SERVER_DIR_HELP.toLocalizedString());
     helpMap.put("disable-default-server",
         LocalizedStrings.ServerLauncher_SERVER_DISABLE_DEFAULT_SERVER_HELP.toLocalizedString());
@@ -163,6 +170,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
   private final AtomicBoolean starting = new AtomicBoolean(false);
 
   private final boolean assignBuckets;
+  private final boolean deletePidFileOnStop;
   private final boolean disableDefaultServer;
   private final boolean force;
   private final boolean help;
@@ -215,8 +223,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
   public static void main(final String... args) {
     try {
       new Builder(args).build().run();
-    } catch (AttachAPINotFoundException e) {
-      System.err.println(e.getMessage());
+    } catch (AttachAPINotFoundException handled) {
+      System.err.println(handled.getMessage());
     }
   }
 
@@ -243,7 +251,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @return the ServerState for this process or null.
    */
   public static ServerState getServerState() {
-    return (getInstance() != null ? getInstance().status() : null);
+    return getInstance() != null ? getInstance().status() : null;
   }
 
   /**
@@ -262,6 +270,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     this.command = builder.getCommand();
     this.assignBuckets = Boolean.TRUE.equals(builder.getAssignBuckets());
     setDebug(Boolean.TRUE.equals(builder.getDebug()));
+    this.deletePidFileOnStop = Boolean.TRUE.equals(builder.getDeletePidFileOnStop());
     this.disableDefaultServer = Boolean.TRUE.equals(builder.getDisableDefaultServer());
     CacheServerLauncher.setDisableDefaultServer(this.disableDefaultServer);
     this.distributedSystemProperties = builder.getDistributedSystemProperties();
@@ -351,7 +360,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     final StringBuilder buffer = new StringBuilder(ServerState.getServerBindAddressAsString(this));
     final String serverPort = ServerState.getServerPortAsString(this);
 
-    if (StringUtils.isNotBlank(serverPort)) {
+    if (isNotBlank(serverPort)) {
       buffer.append("[").append(serverPort).append("]");
     }
 
@@ -436,9 +445,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * 
    * @return a String value indicating the name of this Server's log file.
    */
+  @Override
   public String getLogFileName() {
-    return StringUtils.defaultIfBlank(getMemberName(), DEFAULT_SERVER_LOG_NAME)
-        .concat(DEFAULT_SERVER_LOG_EXT);
+    return defaultIfBlank(getMemberName(), DEFAULT_SERVER_LOG_NAME).concat(DEFAULT_SERVER_LOG_EXT);
   }
 
   /**
@@ -450,7 +459,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    */
   @Override
   public String getMemberName() {
-    return StringUtils.defaultIfBlank(this.memberName, super.getMemberName());
+    return defaultIfBlank(this.memberName, super.getMemberName());
   }
 
   /**
@@ -511,11 +520,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
       final InetAddress localhost = SocketCreator.getLocalHost();
 
       return localhost.getCanonicalHostName();
-    } catch (UnknownHostException ignore) {
-      // TODO determine a better value for the host on which the Server is running to return here...
+    } catch (UnknownHostException handled) {
       // NOTE returning localhost/127.0.0.1 implies the serverBindAddress was null and no IP address
-      // for localhost
-      // could be found
+      // for localhost could be found
       return "localhost/127.0.0.1";
     }
   }
@@ -542,7 +549,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #getServerPort()
    */
   public String getServerPortAsString() {
-    return ObjectUtils.defaultIfNull(getServerPort(), getDefaultServerPort()).toString();
+    return defaultIfNull(getServerPort(), getDefaultServerPort()).toString();
   }
 
   /**
@@ -550,6 +557,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * 
    * @return a String indicating the name for a GemFire Server.
    */
+  @Override
   public String getServiceName() {
     return SERVER_SERVICE_NAME;
   }
@@ -575,7 +583,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    *         configuration meta-data.
    */
   public boolean isSpringXmlLocationSpecified() {
-    return StringUtils.isNotBlank(this.springXmlLocation);
+    return isNotBlank(this.springXmlLocation);
   }
 
   /**
@@ -639,14 +647,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
     if (Command.isUnspecified(command)) {
       usage();
     } else {
-      info(StringUtils.wrap(helpMap.get(command.getName()), 80, ""));
+      info(wrap(helpMap.get(command.getName()), 80, ""));
       info("\n\nusage: \n\n");
-      info(StringUtils.wrap("> java ... " + getClass().getName() + ' ' + usageMap.get(command), 80,
-          "\t\t"));
+      info(wrap("> java ... " + getClass().getName() + ' ' + usageMap.get(command), 80, "\t\t"));
       info("\n\noptions: \n\n");
 
       for (final String option : command.getOptions()) {
-        info(StringUtils.wrap("--" + option + ": " + helpMap.get(option) + '\n', 80, "\t"));
+        info(wrap("--" + option + ": " + helpMap.get(option) + '\n', 80, "\t"));
       }
 
       info("\n\n");
@@ -660,7 +667,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #help(org.apache.geode.distributed.ServerLauncher.Command)
    */
   public void usage() {
-    info(StringUtils.wrap(helpMap.get("launcher"), 80, "\t"));
+    info(wrap(helpMap.get("launcher"), 80, "\t"));
     info("\n\nSTART\n\n");
     help(Command.START);
     info("STATUS\n\n");
@@ -719,7 +726,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #start()
    */
   private boolean isStartable() {
-    return (!isRunning() && this.starting.compareAndSet(false, true));
+    return !isRunning() && this.starting.compareAndSet(false, true);
   }
 
   /**
@@ -810,18 +817,12 @@ public class ServerLauncher extends AbstractLauncher<String> {
             LocalizedStrings.Launcher_Command_START_PID_UNAVAILABLE_ERROR_MESSAGE.toLocalizedString(
                 getServiceName(), getId(), getWorkingDirectory(), e.getMessage()),
             e);
-      } catch (ClusterConfigurationNotAvailableException e) {
-        failOnStart(e);
-        throw e;
-      } catch (RuntimeException e) {
+      } catch (RuntimeException | Error e) {
         failOnStart(e);
         throw e;
       } catch (Exception e) {
         failOnStart(e);
         throw new RuntimeException(e);
-      } catch (Error e) {
-        failOnStart(e);
-        throw e;
       } finally {
         this.starting.set(false);
       }
@@ -857,7 +858,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
       this.cache = null;
     }
     if (this.process != null) {
-      this.process.stop();
+      this.process.stop(this.deletePidFileOnStop);
       this.process = null;
     }
 
@@ -886,7 +887,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    */
   boolean isWaiting(final Cache cache) {
     // return (isRunning() && !getCache().isClosed());
-    return (isRunning() && (cache.getDistributedSystem().isConnected() || cache.isReconnecting()));
+    return isRunning() && (cache.getDistributedSystem().isConnected() || cache.isReconnecting());
   }
 
   /**
@@ -901,9 +902,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
         while (isWaiting(getCache())) {
           try {
             synchronized (this) {
-              wait(500l);
+              wait(500L);
             }
-          } catch (InterruptedException ignore) {
+          } catch (InterruptedException handled) {
+            // loop back around
           }
         }
       } catch (RuntimeException e) {
@@ -926,7 +928,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @see #isDisableDefaultServer()
    */
   protected boolean isDefaultServerEnabled(final Cache cache) {
-    return (cache.getCacheServers().isEmpty() && !isDisableDefaultServer());
+    return cache.getCacheServers().isEmpty() && !isDisableDefaultServer();
   }
 
   /**
@@ -940,7 +942,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
   void startCacheServer(final Cache cache) throws IOException {
     if (isDefaultServerEnabled(cache)) {
       final String serverBindAddress =
-          (getServerBindAddress() == null ? null : getServerBindAddress().getHostAddress());
+          getServerBindAddress() == null ? null : getServerBindAddress().getHostAddress();
       final Integer serverPort = getServerPort();
       CacheServerLauncher.setServerBindAddress(serverBindAddress);
       CacheServerLauncher.setServerPort(serverPort);
@@ -1024,7 +1026,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
    * @return a boolean indicating if the Server is starting or is already running.
    */
   protected boolean isStartingOrRunning() {
-    return (this.starting.get() || isRunning());
+    return this.starting.get() || isRunning();
   }
 
   /**
@@ -1037,7 +1039,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     if (isStartingOrRunning()) {
       debug(
           "Getting status from the ServerLauncher instance that actually launched the GemFire Cache Server.%n");
-      return new ServerState(this, (isRunning() ? Status.ONLINE : Status.STARTING));
+      return new ServerState(this, isRunning() ? Status.ONLINE : Status.STARTING);
     } else if (isPidInProcess() && launcher != null) {
       return launcher.statusInProcess();
     } else if (getPid() != null) {
@@ -1061,7 +1063,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     if (isStartingOrRunning()) {
       debug(
           "Getting status from the ServerLauncher instance that actually launched the GemFire Cache Server.%n");
-      return new ServerState(this, (isRunning() ? Status.ONLINE : Status.STARTING));
+      return new ServerState(this, isRunning() ? Status.ONLINE : Status.STARTING);
     } else {
       return new ServerState(this, Status.NOT_RESPONDING);
     }
@@ -1074,50 +1076,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
       controller.checkPidSupport();
       final String statusJson = controller.status();
       return ServerState.fromJson(statusJson);
-    }
-    // catch (NoClassDefFoundError error) {
-    // if (isAttachAPINotFound(error)) {
-    // throw new
-    // AttachAPINotFoundException(LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE
-    // .toLocalizedString(), error);
-    // }
-    //
-    // throw error;
-    // }
-    catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + getPid());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (MalformedObjectNameException e) { // impossible
-    // // JMX object name is bad
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (PidUnavailableException e) {
-    // // couldn't determine pid from within server JVM
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (UnableToControlProcessException e) {
-      // TODO comment me
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    } catch (InterruptedException e) {
-      // TODO comment me
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    } catch (TimeoutException e) {
-      // TODO comment me
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + getPid());
+    } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException
+        | InterruptedException | TimeoutException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + getPid());
     }
   }
@@ -1125,9 +1090,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
   private ServerState statusWithWorkingDirectory() {
     int parsedPid = 0;
     try {
-      final ProcessController controller = new ProcessControllerFactory().createProcessController(
-          this.controllerParameters, new File(getWorkingDirectory()),
-          ProcessType.SERVER.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+      final ProcessController controller =
+          new ProcessControllerFactory().createProcessController(this.controllerParameters,
+              new File(getWorkingDirectory()), ProcessType.SERVER.getPidFileName());
       parsedPid = controller.getProcessId();
 
       // note: in-process request will go infinite loop unless we do the following
@@ -1140,35 +1105,26 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
       final String statusJson = controller.status();
       return ServerState.fromJson(statusJson);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + parsedPid);
-    } catch (FileNotFoundException e) {
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + parsedPid);
+    } catch (FileNotFoundException handled) {
       // could not find pid file
-      return createNoResponseState(e, "Failed to find process file "
+      return createNoResponseState(handled, "Failed to find process file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
+    } catch (IOException | MBeanInvocationFailedException | UnableToControlProcessException
+        | TimeoutException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + parsedPid);
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
           "Interrupted while trying to communicate with server with process id " + parsedPid);
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
-    } catch (PidUnavailableException e) {
+    } catch (PidUnavailableException handled) {
       // couldn't determine pid from within server JVM
-      return createNoResponseState(e, "Failed to find usable process id within file "
+      return createNoResponseState(handled, "Failed to find usable process id within file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
-    } catch (TimeoutException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
     }
   }
 
@@ -1205,7 +1161,6 @@ public class ServerLauncher extends AbstractLauncher<String> {
       return stopWithWorkingDirectory();
     }
 
-    // TODO give user detailed error message?
     return new ServerState(this, Status.NOT_RESPONDING);
   }
 
@@ -1217,7 +1172,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
       this.cache.close();
       this.cache = null;
       if (this.process != null) {
-        this.process.stop();
+        this.process.stop(this.deletePidFileOnStop);
         this.process = null;
       }
       INSTANCE.compareAndSet(this, null); // note: other thread may return Status.NOT_RESPONDING now
@@ -1235,42 +1190,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
       controller.checkPidSupport();
       controller.stop();
       return new ServerState(this, Status.STOPPED);
-    }
-    // catch (NoClassDefFoundError error) {
-    // if (isAttachAPINotFound(error)) {
-    // throw new
-    // AttachAPINotFoundException(LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE
-    // .toLocalizedString(), error);
-    // }
-    //
-    // throw error;
-    // }
-    catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + getPid());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (MalformedObjectNameException e) { // impossible
-    // // JMX object name is bad
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + getPid());
-    }
-    // catch (PidUnavailableException e) {
-    // // couldn't determine pid from within server JVM
-    // return createNoResponseState(e, "Failed to communicate with server with process id " +
-    // getPid());
-    // }
-    catch (UnableToControlProcessException e) {
-      // TODO comment me
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + getPid());
+    } catch (IOException | MBeanInvocationFailedException
+        | UnableToControlProcessException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + getPid());
     }
   }
@@ -1278,9 +1204,9 @@ public class ServerLauncher extends AbstractLauncher<String> {
   private ServerState stopWithWorkingDirectory() {
     int parsedPid = 0;
     try {
-      final ProcessController controller = new ProcessControllerFactory().createProcessController(
-          this.controllerParameters, new File(getWorkingDirectory()),
-          ProcessType.SERVER.getPidFileName(), READ_PID_FILE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+      final ProcessController controller =
+          new ProcessControllerFactory().createProcessController(this.controllerParameters,
+              new File(getWorkingDirectory()), ProcessType.SERVER.getPidFileName());
       parsedPid = controller.getProcessId();
 
       // NOTE in-process request will go infinite loop unless we do the following
@@ -1293,35 +1219,30 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
       controller.stop();
       return new ServerState(this, Status.STOPPED);
-    } catch (ConnectionFailedException e) {
+    } catch (ConnectionFailedException handled) {
       // failed to attach to server JVM
-      return createNoResponseState(e, "Failed to connect to server with process id " + parsedPid);
-    } catch (FileNotFoundException e) {
+      return createNoResponseState(handled,
+          "Failed to connect to server with process id " + parsedPid);
+    } catch (FileNotFoundException handled) {
       // could not find pid file
-      return createNoResponseState(e, "Failed to find process file "
+      return createNoResponseState(handled, "Failed to find process file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (IOException e) {
-      // failed to open or read file or dir
-      return createNoResponseState(e,
+    } catch (IOException | MBeanInvocationFailedException
+        | UnableToControlProcessException handled) {
+      return createNoResponseState(handled,
           "Failed to communicate with server with process id " + parsedPid);
-    } catch (InterruptedException e) {
+    } catch (InterruptedException handled) {
       Thread.currentThread().interrupt();
-      return createNoResponseState(e,
+      return createNoResponseState(handled,
           "Interrupted while trying to communicate with server with process id " + parsedPid);
-    } catch (MBeanInvocationFailedException e) {
-      // MBean either doesn't exist or method or attribute don't exist
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
-    } catch (PidUnavailableException e) {
+    } catch (PidUnavailableException handled) {
       // couldn't determine pid from within server JVM
-      return createNoResponseState(e, "Failed to find usable process id within file "
-          + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (TimeoutException e) {
-      return createNoResponseState(e, "Timed out trying to find usable process id within file "
+      return createNoResponseState(handled, "Failed to find usable process id within file "
           + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
-    } catch (UnableToControlProcessException e) {
-      return createNoResponseState(e,
-          "Failed to communicate with server with process id " + parsedPid);
+    } catch (TimeoutException handled) {
+      return createNoResponseState(handled,
+          "Timed out trying to find usable process id within file "
+              + ProcessType.SERVER.getPidFileName() + " in " + getWorkingDirectory());
     }
   }
 
@@ -1330,17 +1251,16 @@ public class ServerLauncher extends AbstractLauncher<String> {
     this.running.set(true);
   }
 
-
   private ServerState createNoResponseState(final Exception cause, final String errorMessage) {
     debug(cause);
     return new ServerState(this, Status.NOT_RESPONDING, errorMessage);
   }
 
-  private Properties getOverriddenDefaults() {
+  private Properties getOverriddenDefaults() throws IOException {
     final Properties overriddenDefaults = new Properties();
 
     overriddenDefaults.put(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX.concat(LOG_FILE),
-        getLogFileName());
+        getLogFile().getCanonicalPath());
 
     for (String key : System.getProperties().stringPropertyNames()) {
       if (key.startsWith(ProcessLauncherContext.OVERRIDDEN_DEFAULTS_PREFIX)) {
@@ -1358,7 +1278,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     @Override
-    public File getWorkingDirectory() {
+    public File getDirectory() {
       return new File(ServerLauncher.this.getWorkingDirectory());
     }
 
@@ -1376,7 +1296,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     public ObjectName getNamePattern() {
       try {
         return ObjectName.getInstance("GemFire:type=Member,*");
-      } catch (MalformedObjectNameException | NullPointerException ignore) {
+      } catch (MalformedObjectNameException | NullPointerException handled) {
         return null;
       }
     }
@@ -1421,6 +1341,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
     private Boolean assignBuckets;
     private Boolean debug;
+    private Boolean deletePidFileOnStop;
     private Boolean disableDefaultServer;
     private Boolean force;
     private Boolean help;
@@ -1540,6 +1461,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
 
         setAssignBuckets(options.has("assign-buckets"));
         setDebug(options.has("debug"));
+        setDeletePidFileOnStop(options.has("delete-pid-file-on-stop"));
         setDisableDefaultServer(options.has("disable-default-server"));
         setForce(options.has("force"));
         setHelp(options.has("help"));
@@ -1617,7 +1539,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
           }
         }
 
-        // TODO why are these option not inside the 'if (!isHelping())' conditional block!?
+        // why are these option not inside the 'if (!isHelping())' conditional block?
 
         if (options.hasArgument(CliStrings.START_SERVER__CRITICAL__HEAP__PERCENTAGE)) {
           setCriticalHeapPercentage(Float.parseFloat(ObjectUtils
@@ -1726,7 +1648,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see org.apache.geode.distributed.ServerLauncher.Command
      */
     public Command getCommand() {
-      return ObjectUtils.defaultIfNull(this.command, DEFAULT_COMMAND);
+      return defaultIfNull(this.command, DEFAULT_COMMAND);
     }
 
     /**
@@ -1801,7 +1723,33 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Determines whether a default cache server will be added when the GemFire Server comes online.
+     * Determines whether the Geode Server should delete the pid file when its service stops or when
+     * the JVM exits.
+     *
+     * @return a boolean value indicating if the pid file should be deleted when this service stops
+     *         or when the JVM exits.
+     * @see #setDeletePidFileOnStop(Boolean)
+     */
+    public Boolean getDeletePidFileOnStop() {
+      return this.deletePidFileOnStop;
+    }
+
+    /**
+     * Sets whether the Geode Server should delete the pid file when its service stops or when the
+     * JVM exits.
+     *
+     * @param deletePidFileOnStop a boolean value indicating if the pid file should be deleted when
+     *        this service stops or when the JVM exits.
+     * @return this Builder instance.
+     * @see #getDeletePidFileOnStop()
+     */
+    public Builder setDeletePidFileOnStop(final Boolean deletePidFileOnStop) {
+      this.deletePidFileOnStop = deletePidFileOnStop;
+      return this;
+    }
+
+    /**
+     * Determines whether a default cache server will be added when the Geode Server comes online.
      * 
      * @return a boolean value indicating whether to add a default cache server.
      * @see #setDisableDefaultServer(Boolean)
@@ -1840,11 +1788,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * 
      * @return the boolean value specifying whether or not to overwrite the PID file if it already
      *         exists.
-     * @see org.apache.geode.internal.process.LocalProcessLauncher
      * @see #setForce(Boolean)
      */
     public Boolean getForce() {
-      return ObjectUtils.defaultIfNull(this.force, DEFAULT_FORCE);
+      return defaultIfNull(this.force, DEFAULT_FORCE);
     }
 
     /**
@@ -1854,7 +1801,6 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @param force a boolean value indicating whether to overwrite the PID file when it already
      *        exists.
      * @return this Builder instance.
-     * @see org.apache.geode.internal.process.LocalProcessLauncher
      * @see #getForce()
      */
     public Builder setForce(final Boolean force) {
@@ -1941,7 +1887,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #getMemberName()
      */
     public Builder setMemberName(final String memberName) {
-      if (StringUtils.isBlank(memberName)) {
+      if (isBlank(memberName)) {
         throw new IllegalArgumentException(
             LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE
                 .toLocalizedString("Server"));
@@ -1983,11 +1929,11 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Determines whether the new instance of LocatorLauncher will redirect output to system logs
-     * when starting a Locator.
+     * Determines whether the new instance of ServerLauncher will redirect output to system logs
+     * when starting a Server.
      * 
      * @return a boolean value indicating if output will be redirected to system logs when starting
-     *         a Locator
+     *         a Server
      * 
      * @see #setRedirectOutput(Boolean)
      */
@@ -2005,11 +1951,11 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Sets whether the new instance of LocatorLauncher will redirect output to system logs when
-     * starting a Locator.
+     * Sets whether the new instance of ServerLauncher will redirect output to system logs when
+     * starting a Server.
      * 
      * @param redirectOutput a boolean value indicating if output will be redirected to system logs
-     *        when starting a Locator.
+     *        when starting a Server.
      * @return this Builder instance.
      * @see #getRedirectOutput()
      */
@@ -2047,7 +1993,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #getServerBindAddress()
      */
     public Builder setServerBindAddress(final String serverBindAddress) {
-      if (StringUtils.isBlank(serverBindAddress)) {
+      if (isBlank(serverBindAddress)) {
         this.serverBindAddress = null;
         return this;
       }
@@ -2081,7 +2027,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #setServerPort(Integer)
      */
     public Integer getServerPort() {
-      return ObjectUtils.defaultIfNull(this.serverPort, getDefaultServerPort());
+      return defaultIfNull(this.serverPort, getDefaultServerPort());
     }
 
     boolean isServerPortSetByUser() {
@@ -2144,8 +2090,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #setWorkingDirectory(String)
      */
     public String getWorkingDirectory() {
-      return IOUtils.tryGetCanonicalPathElseGetAbsolutePath(
-          new File(StringUtils.defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY)));
+      return tryGetCanonicalPathElseGetAbsolutePath(
+          new File(defaultIfBlank(this.workingDirectory, DEFAULT_WORKING_DIRECTORY)));
     }
 
     /**
@@ -2162,8 +2108,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see java.io.FileNotFoundException
      */
     public Builder setWorkingDirectory(final String workingDirectory) {
-      if (!(new File(StringUtils.defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY))
-          .isDirectory())) {
+      if (!new File(defaultIfBlank(workingDirectory, DEFAULT_WORKING_DIRECTORY)).isDirectory()) {
         throw new IllegalArgumentException(
             LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
                 .toLocalizedString("Server"),
@@ -2242,6 +2187,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     public Builder setHostNameForClients(String hostNameForClients) {
+      if (isBlank(hostNameForClients)) {
+        throw new IllegalArgumentException(
+            "The hostname used by clients to connect to the Server must have an argument if the --hostname-for-clients command-line option is specified!");
+      }
       this.hostNameForClients = hostNameForClients;
       return this;
     }
@@ -2412,7 +2361,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      */
     void validateOnStart() {
       if (Command.START == getCommand()) {
-        if (StringUtils.isBlank(getMemberName())
+        if (isBlank(getMemberName())
             && !isSet(System.getProperties(), DistributionConfig.GEMFIRE_PREFIX + NAME)
             && !isSet(getDistributedSystemProperties(), NAME)
             && !isSet(loadGemFireProperties(DistributedSystem.getPropertyFileURL()), NAME)) {
@@ -2421,7 +2370,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
                   .toLocalizedString("Server"));
         }
 
-        if (!SystemUtils.CURRENT_DIRECTORY.equals(getWorkingDirectory())) {
+        if (!CURRENT_DIRECTORY.equals(getWorkingDirectory())) {
           throw new IllegalStateException(
               LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE
                   .toLocalizedString("Server"));
@@ -2481,10 +2430,10 @@ public class ServerLauncher extends AbstractLauncher<String> {
     private final String name;
 
     Command(final String name, final String... options) {
-      assert StringUtils.isNotBlank(name) : "The name of the command must be specified!";
+      assert isNotBlank(name) : "The name of the command must be specified!";
       this.name = name;
-      this.options = (options != null ? Collections.unmodifiableList(Arrays.asList(options))
-          : Collections.<String>emptyList());
+      this.options = options != null ? Collections.unmodifiableList(Arrays.asList(options))
+          : Collections.<String>emptyList();
     }
 
     /**
@@ -2496,7 +2445,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      *         valid.
      */
     public static boolean isCommand(final String name) {
-      return (valueOfName(name) != null);
+      return valueOfName(name) != null;
     }
 
     /**
@@ -2508,7 +2457,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see Command#UNSPECIFIED
      */
     public static boolean isUnspecified(final Command command) {
-      return (command == null || command.isUnspecified());
+      return command == null || command.isUnspecified();
     }
 
     /**
@@ -2539,7 +2488,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Gets a set of valid options that can be used with the Locator launcher command when used from
+     * Gets a set of valid options that can be used with the Server launcher command when used from
      * the command-line.
      * 
      * @return a Set of Strings indicating the names of the options available to the Server launcher
@@ -2550,14 +2499,14 @@ public class ServerLauncher extends AbstractLauncher<String> {
     }
 
     /**
-     * Determines whether this Locator launcher command has the specified command-line option.
+     * Determines whether this Server launcher command has the specified command-line option.
      * 
      * @param option a String indicating the name of the command-line option to this command.
      * @return a boolean value indicating whether this command has the specified named command-line
      *         option.
      */
     public boolean hasOption(final String option) {
-      return getOptions().contains(StringUtils.lowerCase(option));
+      return getOptions().contains(lowerCase(option));
     }
 
     /**
@@ -2567,7 +2516,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
      * @see #UNSPECIFIED
      */
     public boolean isUnspecified() {
-      return (this == UNSPECIFIED);
+      return this == UNSPECIFIED;
     }
 
     /**
@@ -2582,8 +2531,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
   }
 
   /**
-   * The ServerState is an immutable type representing the state of the specified Locator at any
-   * given moment in time. The state of the Locator is assessed at the exact moment an instance of
+   * The ServerState is an immutable type representing the state of the specified Server at any
+   * given moment in time. The state of the Server is assessed at the exact moment an instance of
    * this class is constructed.
    * 
    * @see org.apache.geode.distributed.AbstractLauncher.ServiceState
@@ -2612,7 +2561,6 @@ public class ServerLauncher extends AbstractLauncher<String> {
             gfJsonObject.getString(JSON_HOST), gfJsonObject.getString(JSON_PORT),
             gfJsonObject.getString(JSON_MEMBERNAME));
       } catch (GfJsonException e) {
-        // TODO: or should we return OFFLINE?
         throw new IllegalArgumentException("Unable to create ServerStatus from JSON: " + json, e);
       }
     }
@@ -2673,9 +2621,8 @@ public class ServerLauncher extends AbstractLauncher<String> {
       if (system != null) {
         final File logFile = system.getConfig().getLogFile();
         if (logFile != null && logFile.isFile()) {
-          final String logFileCanonicalPath =
-              IOUtils.tryGetCanonicalPathElseGetAbsolutePath(logFile);
-          if (StringUtils.isNotBlank(logFileCanonicalPath)) {
+          final String logFileCanonicalPath = tryGetCanonicalPathElseGetAbsolutePath(logFile);
+          if (isNotBlank(logFileCanonicalPath)) {
             return logFileCanonicalPath;
           }
         }
@@ -2693,7 +2640,7 @@ public class ServerLauncher extends AbstractLauncher<String> {
         if (csList != null && !csList.isEmpty()) {
           final CacheServer cs = csList.get(0);
           final String serverBindAddressAsString = cs.getBindAddress();
-          if (StringUtils.isNotBlank(serverBindAddressAsString)) {
+          if (isNotBlank(serverBindAddressAsString)) {
             return serverBindAddressAsString;
           }
         }
@@ -2711,14 +2658,13 @@ public class ServerLauncher extends AbstractLauncher<String> {
         if (csList != null && !csList.isEmpty()) {
           final CacheServer cs = csList.get(0);
           final String portAsString = String.valueOf(cs.getPort());
-          if (StringUtils.isNotBlank(portAsString)) {
+          if (isNotBlank(portAsString)) {
             return portAsString;
           }
         }
       }
 
-      return (launcher.isDisableDefaultServer() ? StringUtils.EMPTY
-          : launcher.getServerPortAsString());
+      return launcher.isDisableDefaultServer() ? EMPTY : launcher.getServerPortAsString();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
index ffe3be4..4725518 100644
--- a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
+++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalLocator.java
@@ -69,7 +69,6 @@ import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.internal.logging.LogWriterFactory;
 import org.apache.geode.internal.logging.LoggingThreadGroup;
 import org.apache.geode.internal.logging.log4j.LocalizedMessage;
-import org.apache.geode.internal.logging.log4j.LogMarker;
 import org.apache.geode.internal.logging.log4j.LogWriterAppenders;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.net.SocketCreatorFactory;
@@ -525,6 +524,10 @@ public class InternalLocator extends Locator implements ConnectListener {
     return this.config;
   }
 
+  public InternalCache getCache() {
+    return myCache;
+  }
+
   /**
    * Start peer location in this locator. If you plan on starting a distributed system later, this
    * method should be called first so that the distributed system can use this locator.

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
index 1c4104e..2bbe009 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/ClusterConfigurationLoader.java
@@ -17,8 +17,25 @@ package org.apache.geode.internal.cache;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toList;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import java.util.stream.Stream;
+
 import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.logging.log4j.Logger;
+
 import org.apache.geode.UnmodifiableException;
 import org.apache.geode.cache.Cache;
 import org.apache.geode.distributed.internal.ClusterConfigurationService;
@@ -29,28 +46,12 @@ import org.apache.geode.internal.ConfigSource;
 import org.apache.geode.internal.DeployedJar;
 import org.apache.geode.internal.JarDeployer;
 import org.apache.geode.internal.admin.remote.DistributionLocatorId;
+import org.apache.geode.internal.config.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
 import org.apache.geode.management.internal.configuration.domain.Configuration;
 import org.apache.geode.management.internal.configuration.messages.ConfigurationRequest;
 import org.apache.geode.management.internal.configuration.messages.ConfigurationResponse;
-import org.apache.logging.log4j.Logger;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Properties;
-import java.util.Set;
-import java.util.stream.Stream;
 
 public class ClusterConfigurationLoader {
 

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
index f176d22..67c8add 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/cache/GemFireCacheImpl.java
@@ -76,12 +76,9 @@ import javax.transaction.TransactionManager;
 
 import com.sun.jna.Native;
 import com.sun.jna.Platform;
-
 import org.apache.commons.lang.StringUtils;
 import org.apache.logging.log4j.Logger;
-import org.apache.geode.internal.cache.event.EventTracker;
-import org.apache.geode.internal.cache.event.EventTrackerExpiryTask;
-import org.apache.geode.internal.security.SecurityServiceFactory;
+
 import org.apache.geode.CancelCriterion;
 import org.apache.geode.CancelException;
 import org.apache.geode.ForcedDisconnectException;
@@ -177,6 +174,7 @@ import org.apache.geode.internal.SystemTimer;
 import org.apache.geode.internal.cache.control.InternalResourceManager;
 import org.apache.geode.internal.cache.control.InternalResourceManager.ResourceType;
 import org.apache.geode.internal.cache.control.ResourceAdvisor;
+import org.apache.geode.internal.cache.event.EventTrackerExpiryTask;
 import org.apache.geode.internal.cache.execute.util.FindRestEnabledServersFunction;
 import org.apache.geode.internal.cache.extension.Extensible;
 import org.apache.geode.internal.cache.extension.ExtensionPoint;
@@ -204,6 +202,7 @@ import org.apache.geode.internal.cache.xmlcache.CacheXmlParser;
 import org.apache.geode.internal.cache.xmlcache.CacheXmlPropertyResolver;
 import org.apache.geode.internal.cache.xmlcache.PropertyResolver;
 import org.apache.geode.internal.concurrent.ConcurrentHashSet;
+import org.apache.geode.internal.config.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.jndi.JNDIInvoker;
 import org.apache.geode.internal.jta.TransactionManagerImpl;
@@ -213,8 +212,8 @@ import org.apache.geode.internal.logging.LoggingThreadGroup;
 import org.apache.geode.internal.logging.log4j.LocalizedMessage;
 import org.apache.geode.internal.net.SocketCreator;
 import org.apache.geode.internal.offheap.MemoryAllocator;
-import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.security.SecurityService;
+import org.apache.geode.internal.security.SecurityServiceFactory;
 import org.apache.geode.internal.sequencelog.SequenceLoggerImpl;
 import org.apache.geode.internal.tcp.ConnectionTable;
 import org.apache.geode.internal.util.concurrent.FutureResult;

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java b/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java
new file mode 100644
index 0000000..b22f13f
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/internal/config/ClusterConfigurationNotAvailableException.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.config;
+
+/**
+ * Exception thrown during server startup when it requests the locators for shared configuration and
+ * does not receive it.
+ */
+public class ClusterConfigurationNotAvailableException
+    extends org.apache.geode.internal.process.ClusterConfigurationNotAvailableException {
+
+  private static final long serialVersionUID = 771319836094239284L;
+
+  public ClusterConfigurationNotAvailableException(final String message) {
+    super(message);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java b/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
index 3f36244..4b35ce5 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/io/TeePrintStream.java
@@ -34,7 +34,7 @@ public class TeePrintStream extends PrintStream {
 
   @Override
   public String toString() {
-    final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+    StringBuilder sb = new StringBuilder(getClass().getSimpleName());
     sb.append("@").append(System.identityHashCode(this)).append("{");
     sb.append("teeOutputStream=").append(this.teeOut);
     return sb.append("}").toString();

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java b/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
index 2103785..3b5da76 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/AttachProcessUtils.java
@@ -14,10 +14,13 @@
  */
 package org.apache.geode.internal.process;
 
-import org.apache.geode.internal.process.ProcessUtils.InternalProcessUtils;
+import static org.apache.commons.lang.Validate.isTrue;
+
 import com.sun.tools.attach.VirtualMachine;
 import com.sun.tools.attach.VirtualMachineDescriptor;
 
+import org.apache.geode.internal.process.ProcessUtils.InternalProcessUtils;
+
 /**
  * Implementation of the {@link ProcessUtils} SPI that uses the JDK Attach API.
  * 
@@ -25,10 +28,10 @@ import com.sun.tools.attach.VirtualMachineDescriptor;
  */
 class AttachProcessUtils implements InternalProcessUtils {
 
-  AttachProcessUtils() {}
-
   @Override
   public boolean isProcessAlive(final int pid) {
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
     for (VirtualMachineDescriptor vm : VirtualMachine.list()) {
       if (vm.id().equals(String.valueOf(pid))) {
         return true; // found the vm

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java b/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
index 9d2b497..62bded4 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/BlockingProcessStreamReader.java
@@ -14,9 +14,11 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.SystemUtils.LINE_SEPARATOR;
+
 import java.io.BufferedReader;
-import java.io.IOException;
 import java.io.InputStreamReader;
+import java.io.UncheckedIOException;
 
 import org.apache.logging.log4j.Logger;
 
@@ -39,32 +41,11 @@ public class BlockingProcessStreamReader extends ProcessStreamReader {
 
   @Override
   public void run() {
-    final boolean isDebugEnabled = logger.isDebugEnabled();
-    if (isDebugEnabled) {
-      logger.debug("Running {}", this);
-    }
-    BufferedReader reader = null;
     try {
-      reader = new BufferedReader(new InputStreamReader(inputStream));
-      String line;
-      while ((line = reader.readLine()) != null) {
-        this.inputListener.notifyInputLine(line);
-      }
-    } catch (IOException e) {
-      if (isDebugEnabled) {
-        logger.debug("Failure reading from buffered input stream: {}", e.getMessage(), e);
-      }
-    } finally {
-      try {
-        reader.close();
-      } catch (IOException e) {
-        if (isDebugEnabled) {
-          logger.debug("Failure closing buffered input stream reader: {}", e.getMessage(), e);
-        }
-      }
-      if (isDebugEnabled) {
-        logger.debug("Terminating {}", this);
-      }
+      new BufferedReader(new InputStreamReader(inputStream)).lines()
+          .map(line -> line + LINE_SEPARATOR).forEach(this.inputListener::notifyInputLine);
+    } catch (UncheckedIOException e) {
+      logger.debug(e);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java b/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
index 7699cc4..981c460 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ClusterConfigurationNotAvailableException.java
@@ -17,10 +17,14 @@ package org.apache.geode.internal.process;
 /**
  * Exception thrown during server startup when it requests the locators for shared configuration and
  * does not receive it.
- * 
+ *
  * @since GemFire 8.0
+ * @deprecated Please use
+ *             {@link org.apache.geode.internal.config.ClusterConfigurationNotAvailableException}
+ *             instead.
  */
-public class ClusterConfigurationNotAvailableException extends RuntimeException {
+@Deprecated
+public class ClusterConfigurationNotAvailableException extends Exception {
   private static final long serialVersionUID = -3448160213553925462L;
 
   public ClusterConfigurationNotAvailableException(String message) {

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java b/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
index 0c04130..52d7cc7 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ConnectionFailedException.java
@@ -23,23 +23,23 @@ public class ConnectionFailedException extends Exception {
   private static final long serialVersionUID = 5622636452836752700L;
 
   /**
-   * Creates a new <code>ConnectionFailedException</code>.
+   * Creates a new {@code ConnectionFailedException}.
    */
   public ConnectionFailedException(final String message) {
     super(message);
   }
 
   /**
-   * Creates a new <code>ConnectionFailedException</code> that was caused by a given exception
+   * Creates a new {@code ConnectionFailedException} that was caused by a given exception
    */
-  public ConnectionFailedException(final String message, final Throwable thr) {
-    super(message, thr);
+  public ConnectionFailedException(final String message, final Throwable cause) {
+    super(message, cause);
   }
 
   /**
-   * Creates a new <code>ConnectionFailedException</code> that was caused by a given exception
+   * Creates a new {@code ConnectionFailedException} that was caused by a given exception
    */
-  public ConnectionFailedException(final Throwable thr) {
-    super(thr.getMessage(), thr);
+  public ConnectionFailedException(final Throwable cause) {
+    super(cause.getMessage(), cause);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
index 0af8758..efebe70 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControlFileWatchdog.java
@@ -14,6 +14,9 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.notEmpty;
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.File;
 import java.io.IOException;
 
@@ -30,74 +33,83 @@ class ControlFileWatchdog implements Runnable {
   private static final Logger logger = LogService.getLogger();
 
   private static final long STOP_TIMEOUT_MILLIS = 60 * 1000;
-  private static final long SLEEP_MILLIS = 1000;
+  private static final long LOOP_INTERVAL_MILLIS = 1000;
 
-  private final File workingDir;
+  private final File directory;
   private final File file;
   private final ControlRequestHandler requestHandler;
   private final boolean stopAfterRequest;
+
   private Thread thread;
   private boolean alive;
 
-  ControlFileWatchdog(final File workingDir, final String fileName,
+  ControlFileWatchdog(final File directory, final String fileName,
       final ControlRequestHandler requestHandler, final boolean stopAfterRequest) {
-    this.workingDir = workingDir;
-    this.file = new File(this.workingDir, fileName);
+    notNull(directory, "Invalid directory '" + directory + "' specified");
+    notEmpty(fileName, "Invalid fileName '" + fileName + "' specified");
+    notNull(requestHandler, "Invalid requestHandler '" + requestHandler + "' specified");
+
+    this.directory = directory;
+    this.file = new File(directory, fileName);
     this.requestHandler = requestHandler;
     this.stopAfterRequest = stopAfterRequest;
   }
 
   @Override
   public void run() {
-    try { // always set this.alive before stopping
+    try { // always set alive before stopping
       while (isAlive()) {
-        try { // handle handle exceptions
-          Thread.sleep(SLEEP_MILLIS);
-          if (this.file.exists()) {
-            try { // always check stopAfterRequest after main work
-              work();
-            } finally {
-              if (this.stopAfterRequest) {
-                stopMe();
-              }
-            }
-          }
-        } catch (InterruptedException e) {
-          Thread.currentThread().interrupt();
-          // allow to loop around and check isAlive()
-        } catch (IOException e) {
-          logger.error(
-              "Unable to control process with {}. Please add tools.jar from JDK to classpath for improved process control.",
-              this.file);
-          // allow to loop around and check isAlive()
-        }
+        doWork();
       }
     } finally {
       synchronized (this) {
-        this.alive = false;
+        alive = false;
+      }
+    }
+  }
+
+  private void doWork() {
+    try { // handle handle exceptions
+      if (file.exists()) {
+        try { // always check stopAfterRequest after handleRequest
+          handleRequest();
+        } finally {
+          if (stopAfterRequest) {
+            stopMe();
+          }
+        }
       }
+      Thread.sleep(LOOP_INTERVAL_MILLIS);
+    } catch (InterruptedException ignored) {
+      Thread.currentThread().interrupt();
+      // allow to loop around and check isAlive()
+    } catch (IOException ignored) {
+      logger.error(
+          "Unable to control process with {}. Please add tools.jar from JDK to classpath for improved process control.",
+          file);
+      // allow to loop around and check isAlive()
     }
   }
 
-  private void work() throws IOException {
+  private void handleRequest() throws IOException {
     try { // always delete file after invoking handler
-      this.requestHandler.handleRequest();
+      requestHandler.handleRequest();
     } finally {
       try {
-        this.file.delete();
+        file.delete();
       } catch (SecurityException e) {
-        logger.warn("Unable to delete {}", this.file, e);
+        logger.warn("Unable to delete {}", file, e);
       }
     }
   }
 
   void start() {
     synchronized (this) {
-      if (this.thread == null) {
-        this.thread = new Thread(this, createThreadName());
-        this.thread.setDaemon(true);
-        this.alive = true;
-        this.thread.start();
+      if (thread == null) {
+        thread = new Thread(this, createThreadName());
+        thread.setDaemon(true);
+        alive = true;
+        thread.start();
       }
     }
   }
@@ -105,13 +117,13 @@ class ControlFileWatchdog implements Runnable {
   void stop() throws InterruptedException {
     Thread stopping = null;
     synchronized (this) {
-      if (this.thread != null) {
-        this.alive = false;
-        if (this.thread != Thread.currentThread()) {
-          this.thread.interrupt();
-          stopping = this.thread;
+      if (thread != null) {
+        alive = false;
+        if (thread != Thread.currentThread()) {
+          thread.interrupt();
+          stopping = thread;
         }
-        this.thread = null;
+        thread = null;
       }
     }
     if (stopping != null) {
@@ -121,39 +133,39 @@ class ControlFileWatchdog implements Runnable {
 
   boolean isAlive() {
     synchronized (this) {
-      return this.alive;
+      return alive;
     }
   }
 
   private void stopMe() {
     synchronized (this) {
-      if (this.thread != null) {
-        this.alive = false;
-        this.thread = null;
+      if (thread != null) {
+        alive = false;
+        thread = null;
       }
     }
   }
 
   @Override
   public String toString() {
-    final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
-    sb.append("@").append(System.identityHashCode(this)).append("{");
-    sb.append("workingDir=").append(this.workingDir);
-    sb.append(", file=").append(this.file);
-    sb.append(", alive=").append(this.alive);
-    sb.append(", stopAfterRequest=").append(this.stopAfterRequest);
-    return sb.append("}").toString();
+    StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+    sb.append('@').append(System.identityHashCode(this)).append('{');
+    sb.append("directory=").append(directory);
+    sb.append(", file=").append(file);
+    sb.append(", alive=").append(alive); // not synchronized
+    sb.append(", stopAfterRequest=").append(stopAfterRequest);
+    return sb.append('}').toString();
   }
 
   private String createThreadName() {
-    return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + " monitoring "
-        + this.file.getName();
+    return getClass().getSimpleName() + '@' + Integer.toHexString(hashCode()) + " monitoring "
+        + file.getName();
   }
 
   /**
    * Defines the callback to be invoked when the control file exists.
    */
   interface ControlRequestHandler {
-    public void handleRequest() throws IOException;
+    void handleRequest() throws IOException;
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
index 246c1e8..a49d3a6 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControlNotificationHandler.java
@@ -24,7 +24,8 @@ import org.apache.geode.distributed.AbstractLauncher.ServiceState;
  * @since GemFire 8.0
  */
 public interface ControlNotificationHandler {
-  public void handleStop();
 
-  public ServiceState<?> handleStatus();
+  void handleStop();
+
+  ServiceState<?> handleStatus();
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java b/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
index 7641ed3..2fdd116 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ControllableProcess.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
@@ -25,65 +27,54 @@ import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
 
 /**
- * Exists inside a process launched by ServerLauncher or LocatorLauncher. Creates the PID file and
- * ControlFileWatchdogs to monitor working directory for creation of stop or status request files.
+ * Creates the {@link PidFile} and uses {@link ControlFileWatchdog} to monitor the directory for
+ * creation of stop or status request files.
  * 
  * @since GemFire 8.0
  */
 public class ControllableProcess {
   private static final Logger logger = LogService.getLogger();
 
-  private final File workingDir;
-  private final File pidFile;
+  private final File directory;
   private final LocalProcessLauncher launcher;
   private final ControlFileWatchdog stopRequestFileWatchdog;
   private final ControlFileWatchdog statusRequestFileWatchdog;
 
-  public ControllableProcess(final ControlNotificationHandler handler, final File workingDir,
-      final ProcessType processType, boolean force)
+  public ControllableProcess(final ControlNotificationHandler handler, final File directory,
+      final ProcessType processType, final boolean force)
       throws FileAlreadyExistsException, IOException, PidUnavailableException {
-    this.workingDir = workingDir;
-    this.pidFile = new File(this.workingDir, processType.getPidFileName());
-
-    deleteFiles(this.workingDir, processType);
-
-    this.launcher = new LocalProcessLauncher(this.pidFile, force);
+    this(directory, processType, force, createPidFile(directory, processType),
+        createStopHandler(handler), createStatusHandler(handler, directory, processType));
+  }
 
-    final ControlRequestHandler stopHandler = new ControlRequestHandler() {
-      @Override
-      public void handleRequest() {
-        handler.handleStop();
-      }
-    };
-    final ControlRequestHandler statusHandler = new ControlRequestHandler() {
-      @Override
-      public void handleRequest() throws IOException {
-        final ServiceState<?> state = handler.handleStatus();
-        final File statusFile = new File(workingDir, processType.getStatusFileName());
-        if (statusFile.exists()) {
-          statusFile.delete();
-        }
-        final File statusFileTmp = new File(workingDir, processType.getStatusFileName() + ".tmp");
-        if (statusFileTmp.exists()) {
-          statusFileTmp.delete();
-        }
-        boolean created = statusFileTmp.createNewFile();
-        assert created;
-        final FileWriter writer = new FileWriter(statusFileTmp);
-        writer.write(state.toJson());
-        writer.flush();
-        writer.close();
-        boolean renamed = statusFileTmp.renameTo(statusFile);
-        assert renamed;
-      }
-    };
+  private ControllableProcess(final File directory, final ProcessType processType,
+      final boolean force, final File pidFile, final ControlRequestHandler stopHandler,
+      final ControlRequestHandler statusHandler)
+      throws FileAlreadyExistsException, IOException, PidUnavailableException {
+    this(directory, processType, createLocalProcessLauncher(pidFile, force),
+        createStopRequestFileWatchdog(directory, processType, stopHandler),
+        createStatusRequestFileWatchdog(directory, processType, statusHandler));
+  }
 
-    this.stopRequestFileWatchdog = new ControlFileWatchdog(workingDir,
-        processType.getStopRequestFileName(), stopHandler, false);
-    this.stopRequestFileWatchdog.start();
-    this.statusRequestFileWatchdog = new ControlFileWatchdog(workingDir,
-        processType.getStatusRequestFileName(), statusHandler, false);
-    this.statusRequestFileWatchdog.start();
+  ControllableProcess(final File directory, final ProcessType processType,
+      final LocalProcessLauncher launcher, final ControlFileWatchdog stopRequestFileWatchdog,
+      final ControlFileWatchdog statusRequestFileWatchdog) {
+    notNull(directory, "Invalid directory '" + directory + "' specified");
+    notNull(processType, "Invalid processType '" + processType + "' specified");
+    notNull(launcher, "Invalid launcher '" + launcher + "' specified");
+    notNull(stopRequestFileWatchdog,
+        "Invalid stopRequestFileWatchdog '" + stopRequestFileWatchdog + "' specified");
+    notNull(statusRequestFileWatchdog,
+        "Invalid statusRequestFileWatchdog '" + statusRequestFileWatchdog + "' specified");
+
+    this.directory = directory;
+    this.launcher = launcher;
+    this.stopRequestFileWatchdog = stopRequestFileWatchdog;
+    this.statusRequestFileWatchdog = statusRequestFileWatchdog;
+
+    deleteFiles(directory, processType);
+    stopRequestFileWatchdog.start();
+    statusRequestFileWatchdog.start();
   }
 
   /**
@@ -92,7 +83,7 @@ public class ControllableProcess {
    * @return the process id (PID)
    */
   public int getPid() {
-    return this.launcher.getPid();
+    return launcher.getPid();
   }
 
   /**
@@ -101,38 +92,115 @@ public class ControllableProcess {
    * @return the PID file
    */
   public File getPidFile() {
-    return this.launcher.getPidFile();
+    return launcher.getPidFile();
+  }
+
+  public File getDirectory() {
+    return directory;
   }
 
   public void stop() {
+    boolean interrupted = false;
     try {
-      this.statusRequestFileWatchdog.stop();
-    } catch (InterruptedException e) {
-      logger.warn("Interrupted while stopping status handler for controllable process.", e);
+      interrupted = stop(statusRequestFileWatchdog);
+      interrupted = stop(stopRequestFileWatchdog) || interrupted;
+      launcher.close();
     } finally {
-      try {
-        this.stopRequestFileWatchdog.stop();
-      } catch (InterruptedException e) {
-        logger.warn("Interrupted while stopping stop handler for controllable process.", e);
+      if (interrupted) {
+        Thread.currentThread().interrupt();
       }
-      this.launcher.close();
     }
   }
 
-  protected File getWorkingDir() {
-    return this.workingDir;
+  public void stop(final boolean deletePidFileOnStop) {
+    boolean interrupted = false;
+    try {
+      interrupted = stop(statusRequestFileWatchdog);
+      interrupted = stop(stopRequestFileWatchdog) || interrupted;
+      launcher.close(deletePidFileOnStop);
+    } finally {
+      if (interrupted) {
+        Thread.currentThread().interrupt();
+      }
+    }
+  }
+
+  private boolean stop(final ControlFileWatchdog fileWatchdog) {
+    boolean interrupted = false;
+    try {
+      fileWatchdog.stop();
+    } catch (InterruptedException e) {
+      interrupted = true;
+      logger.warn("Interrupted while stopping status handler for controllable process.", e);
+    }
+    return interrupted;
   }
 
-  private static void deleteFiles(final File workingDir, final ProcessType processType) {
-    deleteFile(workingDir, processType.getStatusRequestFileName());
-    deleteFile(workingDir, processType.getStatusFileName());
-    deleteFile(workingDir, processType.getStopRequestFileName());
+  private void deleteFiles(final File directory, final ProcessType processType) {
+    deleteFile(directory, processType.getStatusRequestFileName());
+    deleteFile(directory, processType.getStatusFileName());
+    deleteFile(directory, processType.getStopRequestFileName());
   }
 
-  private static void deleteFile(final File workingDir, final String fileName) {
-    final File file = new File(workingDir, fileName);
+  private void deleteFile(final File directory, final String fileName) {
+    File file = new File(directory, fileName);
     if (file.exists()) {
       file.delete();
     }
   }
+
+  private static File createPidFile(final File directory, final ProcessType processType) {
+    return new File(directory, processType.getPidFileName());
+  }
+
+  private static LocalProcessLauncher createLocalProcessLauncher(final File pidFile,
+      final boolean force) throws FileAlreadyExistsException, IOException, PidUnavailableException {
+    return new LocalProcessLauncher(pidFile, force);
+  }
+
+  private static ControlRequestHandler createStopHandler(final ControlNotificationHandler handler) {
+    return handler::handleStop;
+  }
+
+  private static ControlRequestHandler createStatusHandler(final ControlNotificationHandler handler,
+      final File directory, final ProcessType processType) {
+    return () -> {
+      ServiceState<?> state = handler.handleStatus();
+
+      File statusFile = new File(directory, processType.getStatusFileName());
+      if (statusFile.exists()) {
+        boolean deleted = statusFile.delete();
+        assert deleted;
+      }
+
+      File statusFileTmp = new File(directory, processType.getStatusFileName() + ".tmp");
+      if (statusFileTmp.exists()) {
+        boolean deleted = statusFileTmp.delete();
+        assert deleted;
+      }
+
+      boolean created = statusFileTmp.createNewFile();
+      assert created;
+
+      FileWriter writer = new FileWriter(statusFileTmp);
+      writer.write(state.toJson());
+      writer.flush();
+      writer.close();
+
+      boolean renamed = statusFileTmp.renameTo(statusFile);
+      assert renamed;
+    };
+  }
+
+  private static ControlFileWatchdog createStopRequestFileWatchdog(final File directory,
+      final ProcessType processType, final ControlRequestHandler stopHandler) {
+    return new ControlFileWatchdog(directory, processType.getStopRequestFileName(), stopHandler,
+        false);
+  }
+
+  private static ControlFileWatchdog createStatusRequestFileWatchdog(final File directory,
+      final ProcessType processType, final ControlRequestHandler statusHandler) {
+    return new ControlFileWatchdog(directory, processType.getStatusRequestFileName(), statusHandler,
+        false);
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java b/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
index 4bb6d57..19be21d 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/FileAlreadyExistsException.java
@@ -24,23 +24,23 @@ public class FileAlreadyExistsException extends Exception {
   private static final long serialVersionUID = 5471082555536094256L;
 
   /**
-   * Creates a new <code>FileAlreadyExistsException</code>.
+   * Creates a new {@code FileAlreadyExistsException}.
    */
   public FileAlreadyExistsException(final String message) {
     super(message);
   }
 
   /**
-   * Creates a new <code>FileAlreadyExistsException</code> that was caused by a given exception
+   * Creates a new {@code FileAlreadyExistsException} that was caused by a given exception
    */
-  public FileAlreadyExistsException(final String message, final Throwable thr) {
-    super(message, thr);
+  public FileAlreadyExistsException(final String message, final Throwable cause) {
+    super(message, cause);
   }
 
   /**
-   * Creates a new <code>FileAlreadyExistsException</code> that was caused by a given exception
+   * Creates a new {@code FileAlreadyExistsException} that was caused by a given exception
    */
-  public FileAlreadyExistsException(final Throwable thr) {
-    super(thr.getMessage(), thr);
+  public FileAlreadyExistsException(final Throwable cause) {
+    super(cause.getMessage(), cause);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java b/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
index 0beb9ff..d181894 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/FileControllerParameters.java
@@ -25,7 +25,8 @@ import org.apache.geode.internal.process.ProcessController.Arguments;
  * @since GemFire 8.0
  */
 interface FileControllerParameters extends Arguments {
-  public File getPidFile();
 
-  public File getWorkingDirectory();
+  File getPidFile();
+
+  File getDirectory();
 }


[03/23] geode git commit: GEODE-3328 Properties to set Key/Trust Store Type for SSL configuration - add to docs This closes #703

Posted by zh...@apache.org.
GEODE-3328 Properties to set Key/Trust Store Type for SSL configuration - add to docs
This closes #703


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/8a6e309f
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/8a6e309f
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/8a6e309f

Branch: refs/heads/feature/GEODE-3304
Commit: 8a6e309fcf083ee0420c2cbd0d080754ab3a0070
Parents: 08154dd
Author: Dave Barnes <db...@pivotal.io>
Authored: Wed Aug 9 15:22:22 2017 -0700
Committer: Dave Barnes <db...@pivotal.io>
Committed: Thu Aug 10 12:07:48 2017 -0700

----------------------------------------------------------------------
 geode-docs/managing/security/implementing_ssl.html.md.erb  | 3 +++
 geode-docs/reference/topics/gemfire_properties.html.md.erb | 7 +++++++
 2 files changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/8a6e309f/geode-docs/managing/security/implementing_ssl.html.md.erb
----------------------------------------------------------------------
diff --git a/geode-docs/managing/security/implementing_ssl.html.md.erb b/geode-docs/managing/security/implementing_ssl.html.md.erb
index 4894de7..5cf2517 100644
--- a/geode-docs/managing/security/implementing_ssl.html.md.erb
+++ b/geode-docs/managing/security/implementing_ssl.html.md.erb
@@ -101,6 +101,9 @@ any protocol that is enabled by default in the configured JSSE provider.</dd>
 <dt>**ssl-truststore, ssl-truststore-password**</dt>
 <dd>The path to the trust store and the trust store password, specified as strings</dd>
 
+<dt>**ssl-keystore-type, ssl-truststore-type**</dt>
+<dd>The types of the key store and trust store, specified as strings. The default for both is "JKS", indicating a Java key store or trust store.</dd>
+
 ### Example: secure communications throughout
 
 To implement secure SSL communications throughout an entire distributed system, each process should

http://git-wip-us.apache.org/repos/asf/geode/blob/8a6e309f/geode-docs/reference/topics/gemfire_properties.html.md.erb
----------------------------------------------------------------------
diff --git a/geode-docs/reference/topics/gemfire_properties.html.md.erb b/geode-docs/reference/topics/gemfire_properties.html.md.erb
index c5030b9..238803e 100644
--- a/geode-docs/reference/topics/gemfire_properties.html.md.erb
+++ b/geode-docs/reference/topics/gemfire_properties.html.md.erb
@@ -653,6 +653,13 @@ Any security-related (properties that begin with <code class="ph codeph">securit
 <td></td>
 </tr>
 
+<tr>
+<td>ssl-keystore-type, ssl-truststore-type</td>
+<td>Strings. Type of key store or trust store. "JKS" indicates Java. One common alternative is "pkcs12".</td>
+<td>S, L</td>
+<td>JKS</td>
+</tr>
+
 <tr class="even">
 <td>start-dev-rest-api</td>
 <td>If set to true, then the developer REST API service will be started when cache is created. REST service can be configured using <code class="ph codeph">http-service-port</code> and <code class="ph codeph">http-service-bind-address</code> properties.</td>


[08/23] geode git commit: GEODE-3396 pub-tools support for product name & version variables, delete local Bookbinder helpers.

Posted by zh...@apache.org.
GEODE-3396 pub-tools support for product name & version variables, delete local Bookbinder helpers.


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/beebb65a
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/beebb65a
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/beebb65a

Branch: refs/heads/feature/GEODE-3304
Commit: beebb65a3bf8a07f227af265befbdeca3e4050ec
Parents: 7352fcc
Author: Dave Barnes <db...@pivotal.io>
Authored: Thu Aug 10 17:11:50 2017 -0700
Committer: Dave Barnes <db...@pivotal.io>
Committed: Thu Aug 10 17:11:50 2017 -0700

----------------------------------------------------------------------
 .../master_middleman/bookbinder_helpers.rb      | 298 -------------------
 1 file changed, 298 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/beebb65a/geode-book/master_middleman/bookbinder_helpers.rb
----------------------------------------------------------------------
diff --git a/geode-book/master_middleman/bookbinder_helpers.rb b/geode-book/master_middleman/bookbinder_helpers.rb
deleted file mode 100644
index 817875c..0000000
--- a/geode-book/master_middleman/bookbinder_helpers.rb
+++ /dev/null
@@ -1,298 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-require 'bookbinder/code_example_reader'
-require 'bookbinder/ingest/cloner_factory'
-require 'bookbinder/ingest/git_accessor'
-require 'bookbinder/local_filesystem_accessor'
-require 'date'
-require_relative 'archive_drop_down_menu'
-require_relative 'quicklinks_renderer'
-
-I18n.enforce_available_locales = false
-
-module Bookbinder
-  class Helpers < ::Middleman::Extension
-    # class << self
-    #   def registered(app)
-    #     app.helpers HelperMethods
-    #   end
-
-    #   alias :included :registered
-    # end
-
-    module HelperMethods
-
-      def yield_for_code_snippet(from: nil, at: nil)
-        cloner_factory = Ingest::ClonerFactory.new({out: $stdout},
-                                                   LocalFilesystemAccessor.new,
-                                                   Ingest::GitAccessor.new)
-
-        cloner = cloner_factory.produce(config[:local_repo_dir])
-        code_example_reader = CodeExampleReader.new({out: $stdout},
-                                                    LocalFilesystemAccessor.new)
-        working_copy = cloner.call(source_repo_name: from,
-                                   source_ref: 'master',
-                                   destination_parent_dir: config[:workspace])
-
-        snippet, language = code_example_reader.get_snippet_and_language_at(at, working_copy)
-
-        delimiter = '```'
-
-        snippet.prepend("#{delimiter}#{language}\n").concat("\n#{delimiter}")
-      end
-
-      def elastic_search?
-        !!config[:elastic_search]
-      end
-
-      def yield_for_subnav
-        partial "subnavs/#{subnav_template_name}"
-      end
-
-      def yield_for_archive_drop_down_menu
-        menu = ArchiveDropDownMenu.new(
-          config[:archive_menu],
-          current_path: current_page.path
-        )
-        unless menu.empty?
-          partial 'archive_menus/default', locals: { menu_title: menu.title,
-                                                     dropdown_links: menu.dropdown_links }
-        end
-      end
-
-      def exclude_feedback
-        current_page.add_metadata({page: {feedback_disabled: true}})
-      end
-
-      def yield_for_feedback
-        partial 'layouts/feedback' if config[:feedback_enabled] && !current_page.metadata[:page][:feedback_disabled]
-      end
-
-      def exclude_repo_link
-        current_page.add_metadata({page: {repo_link_disabled: true}})
-      end
-
-      def render_repo_link
-        if config[:repo_link_enabled] && repo_url && !current_page.metadata[:page][:repo_link_disabled]
-          "<a id='repo-link' href='#{repo_url}'>View the source for this page in GitHub</a>"
-        end
-      end
-
-      def mermaid_diagram(&blk)
-        escaped_text = capture(&blk).gsub('-','\-')
-
-        @_out_buf.concat "<div class='mermaid'>#{escaped_text}</div>"
-      end
-
-      def modified_date(default_date: nil)
-        parsed_default_date = Time.parse(default_date).utc if default_date
-
-        date = page_last_modified_date || parsed_default_date
-
-        "Page last updated: <span data-behavior=\"DisplayModifiedDate\" data-modified-date=\"#{date.to_i}000\"></span>" if date
-      end
-
-      def breadcrumbs
-        page_chain = add_ancestors_of(current_page, [])
-        breadcrumbs = page_chain.map do |page|
-          make_breadcrumb(page, page == current_page)
-        end.compact
-        return if breadcrumbs.size < 2
-        return content_tag :ul, breadcrumbs.reverse.join(' '), class: 'breadcrumbs'
-      end
-
-      def vars
-        OpenStruct.new config[:template_variables]
-      end
-
-      ## Geode helpers (start)
-      def geode_product_name
-        current_page.data.title= vars.geode_product_name
-      end
-
-      def geode_product_name_long
-        current_page.data.title= vars.geode_product_name_long
-      end
-
-      def geode_product_version
-        current_page.data.title= vars.geode_product_version
-      end
-
-      def set_title(*args)
-        current_page.data.title= args.join(' ')
-      end
-      ## Geode helpers (end)
-
-      def product_info
-        config[:product_info].fetch(template_key, {})
-      end
-
-      def production_host
-        config[:production_host]
-      end
-
-      def quick_links
-        page_src = File.read(current_page.source_file)
-        quicklinks_renderer = QuicklinksRenderer.new(vars)
-        Redcarpet::Markdown.new(quicklinks_renderer).render(page_src)
-      end
-
-      def owners
-        html_resources = sitemap.resources.select { |r| r.path.end_with?('.html') }
-        html_resources.each.with_object({}) { |resource, owners|
-          owners[resource.path] = Array(resource.data['owner'])
-        }
-      end
-
-      def template_key
-        decreasingly_specific_namespaces.detect { |ns|
-          config[:subnav_templates].has_key?(ns)
-        }
-      end
-
-      def body_classes(path=current_path.dup, options={})
-        if path.is_a? Hash
-          options = path
-          path = current_path.dup
-        end
-        basename = File.basename(path)
-        dirname = File.dirname(path).gsub('.', '_')
-        page_classes(File.join(dirname, basename), options)
-      end
-
-      private
-
-      def subnav_template_name
-        config[:subnav_templates][template_key] || 'default'
-      end
-
-      def decreasingly_specific_namespaces
-        body_classes(numeric_prefix: numeric_class_prefix).
-          split(' ').reverse.drop(1).
-          map {|ns| ns.sub(/^#{numeric_class_prefix}/, '')}
-      end
-
-      def numeric_class_prefix
-        'NUMERIC_CLASS_PREFIX'
-      end
-
-      def page_last_modified_date
-        git_accessor = Ingest::GitAccessor.new
-
-        current_date = if current_page.data.dita
-          git_accessor.author_date(preprocessing_path(current_page.source_file), dita: true)
-        else
-          git_accessor.author_date(current_page.source_file)
-        end
-
-        current_date.utc if current_date
-      end
-
-      def repo_url
-        nested_dir, filename = parse_out_nested_dir_and_filename
-
-        repo_dir = match_repo_dir(nested_dir)
-        page_repo_config = config[:repo_links][repo_dir]
-
-        if page_repo_config && page_repo_config['ref']
-          org_repo = Pathname(page_repo_config['repo'])
-          ref = Pathname(page_repo_config['ref'])
-          at_path = at_path(page_repo_config)
-          nested_dir = extract_nested_directory(nested_dir, repo_dir)
-
-          "http://github.com/#{org_repo.join(Pathname('tree'), ref, Pathname(nested_dir), at_path, source_file(filename))}"
-        end
-      end
-
-      def match_repo_dir(nested_dir)
-        config[:repo_links].keys
-          .select{ |key| nested_dir.match(/^#{key}/) }
-          .sort_by{ |key| key.length }
-          .last
-      end
-
-      def source_file(filename)
-        fs = LocalFilesystemAccessor.new
-
-        if current_page.data.dita
-          source_filename = "#{filename}.xml"
-
-          if fs.source_file_exists?(Pathname(preprocessing_path(current_page.source_file)).dirname,
-                                             source_filename)
-            source_filename
-          else
-            ''
-          end
-        else
-          "#{filename}.html.md.erb"
-        end
-      end
-
-      def preprocessing_path(current_source_path)
-        root_path, nested_repo_path = current_source_path.split('source')
-
-        root_path.gsub!('/output/master_middleman', '')
-
-        "#{root_path}output/preprocessing/sections#{nested_repo_path}"
-      end
-
-      def parse_out_nested_dir_and_filename
-        current_page.path
-          .match(/\/?(.*?)\/?([^\/]*)\.html$?/)
-          .captures
-      end
-
-      def extract_nested_directory(nested_dir, repo_dir)
-        nested_dir = nested_dir.gsub("#{repo_dir}", '')
-        nested_dir = nested_dir.sub('/', '') if nested_dir[0] == '/'
-
-        nested_dir
-      end
-
-      def at_path(page_repo_config)
-        path = page_repo_config['at_path'] || ""
-
-        Pathname(path)
-      end
-
-      def add_ancestors_of(page, ancestors)
-        if page
-          add_ancestors_of(page.parent, ancestors + [page])
-        else
-          ancestors
-        end
-      end
-
-      def make_breadcrumb(page, is_current_page)
-        return nil unless (text = page.data.breadcrumb || page.data.title)
-        if is_current_page
-          css_class = 'active'
-          link = content_tag :span, text
-        else
-          link = link_to(text, '/' + page.path)
-        end
-        content_tag :li, link, :class => css_class
-      end
-    end
-    
-    helpers HelperMethods
-    
-
-  end
-end
-::Middleman::Extensions.register(:bookbinder, Bookbinder::Helpers)


[06/23] geode git commit: GEODE-3328: refactor ConnectCommand

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
index fd95387..3e1053a 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartMemberUtils.java
@@ -83,16 +83,17 @@ public class StartMemberUtils {
   }
 
   static void addGemFirePropertyFile(final List<String> commandLine,
-      final String gemfirePropertiesPathname) {
-    if (org.apache.geode.internal.lang.StringUtils.isNotBlank(gemfirePropertiesPathname)) {
-      commandLine.add("-DgemfirePropertyFile=" + gemfirePropertiesPathname);
+      final File gemfirePropertiesFile) {
+    if (gemfirePropertiesFile != null) {
+      commandLine.add("-DgemfirePropertyFile=" + gemfirePropertiesFile.getAbsolutePath());
     }
   }
 
   static void addGemFireSecurityPropertyFile(final List<String> commandLine,
-      final String gemfireSecurityPropertiesPathname) {
-    if (org.apache.geode.internal.lang.StringUtils.isNotBlank(gemfireSecurityPropertiesPathname)) {
-      commandLine.add("-DgemfireSecurityPropertyFile=" + gemfireSecurityPropertiesPathname);
+      final File gemfireSecurityPropertiesFile) {
+    if (gemfireSecurityPropertiesFile != null) {
+      commandLine
+          .add("-DgemfireSecurityPropertyFile=" + gemfireSecurityPropertiesFile.getAbsolutePath());
     }
   }
 

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
index 432a065..9b743c8 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
@@ -142,14 +142,14 @@ public class StartServerCommand implements GfshCommand {
           help = CliStrings.START_SERVER__MESSAGE__TIME__TO__LIVE__HELP) final Integer messageTimeToLive,
       @CliOption(key = CliStrings.START_SERVER__OFF_HEAP_MEMORY_SIZE,
           help = CliStrings.START_SERVER__OFF_HEAP_MEMORY_SIZE__HELP) final String offHeapMemorySize,
-      @CliOption(key = CliStrings.START_SERVER__PROPERTIES, optionContext = ConverterHint.FILE_PATH,
-          help = CliStrings.START_SERVER__PROPERTIES__HELP) String gemfirePropertiesPathname,
+      @CliOption(key = CliStrings.START_SERVER__PROPERTIES, optionContext = ConverterHint.FILE,
+          help = CliStrings.START_SERVER__PROPERTIES__HELP) File gemfirePropertiesFile,
       @CliOption(key = CliStrings.START_SERVER__REBALANCE, unspecifiedDefaultValue = "false",
           specifiedDefaultValue = "true",
           help = CliStrings.START_SERVER__REBALANCE__HELP) final Boolean rebalance,
       @CliOption(key = CliStrings.START_SERVER__SECURITY_PROPERTIES,
-          optionContext = ConverterHint.FILE_PATH,
-          help = CliStrings.START_SERVER__SECURITY_PROPERTIES__HELP) String gemfireSecurityPropertiesPathname,
+          optionContext = ConverterHint.FILE,
+          help = CliStrings.START_SERVER__SECURITY_PROPERTIES__HELP) File gemfireSecurityPropertiesFile,
       @CliOption(key = CliStrings.START_SERVER__SERVER_BIND_ADDRESS,
           unspecifiedDefaultValue = CacheServer.DEFAULT_BIND_ADDRESS,
           help = CliStrings.START_SERVER__SERVER_BIND_ADDRESS__HELP) final String serverBindAddress,
@@ -206,23 +206,16 @@ public class StartServerCommand implements GfshCommand {
             CliStrings.format(CliStrings.CACHE_XML_NOT_FOUND_MESSAGE, cacheXmlPathname));
       }
 
-      gemfirePropertiesPathname = CliUtil.resolvePathname(gemfirePropertiesPathname);
-
-      if (StringUtils.isNotBlank(gemfirePropertiesPathname)
-          && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) {
+      if (gemfirePropertiesFile != null && !gemfirePropertiesFile.exists()) {
         return ResultBuilder.createUserErrorResult(
             CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, StringUtils.EMPTY,
-                gemfirePropertiesPathname));
+                gemfirePropertiesFile.getAbsolutePath()));
       }
 
-      gemfireSecurityPropertiesPathname =
-          CliUtil.resolvePathname(gemfireSecurityPropertiesPathname);
-
-      if (StringUtils.isNotBlank(gemfireSecurityPropertiesPathname)
-          && !IOUtils.isExistingPathname(gemfireSecurityPropertiesPathname)) {
+      if (gemfireSecurityPropertiesFile != null && !gemfireSecurityPropertiesFile.exists()) {
         return ResultBuilder.createUserErrorResult(
             CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security ",
-                gemfireSecurityPropertiesPathname));
+                gemfireSecurityPropertiesFile.getAbsolutePath()));
       }
 
       File serverPidFile = new File(workingDirectory, ProcessType.SERVER.getPidFileName());
@@ -309,9 +302,8 @@ public class StartServerCommand implements GfshCommand {
       ServerLauncher serverLauncher = serverLauncherBuilder.build();
 
       String[] serverCommandLine = createStartServerCommandLine(serverLauncher,
-          gemfirePropertiesPathname, gemfireSecurityPropertiesPathname, gemfireProperties,
-          classpath, includeSystemClasspath, jvmArgsOpts, disableExitWhenOutOfMemory, initialHeap,
-          maxHeap);
+          gemfirePropertiesFile, gemfireSecurityPropertiesFile, gemfireProperties, classpath,
+          includeSystemClasspath, jvmArgsOpts, disableExitWhenOutOfMemory, initialHeap, maxHeap);
 
       if (getGfsh().getDebug()) {
         getGfsh().logInfo(StringUtils.join(serverCommandLine, StringUtils.SPACE), null);
@@ -428,7 +420,7 @@ public class StartServerCommand implements GfshCommand {
   }
 
   String[] createStartServerCommandLine(final ServerLauncher launcher,
-      final String gemfirePropertiesPathname, final String gemfireSecurityPropertiesPathname,
+      final File gemfirePropertiesFile, final File gemfireSecurityPropertiesFile,
       final Properties gemfireProperties, final String userClasspath,
       final Boolean includeSystemClasspath, final String[] jvmArgsOpts,
       final Boolean disableExitWhenOutOfMemory, final String initialHeap, final String maxHeap)
@@ -441,8 +433,8 @@ public class StartServerCommand implements GfshCommand {
     commandLine.add(getServerClasspath(Boolean.TRUE.equals(includeSystemClasspath), userClasspath));
 
     StartMemberUtils.addCurrentLocators(this, commandLine, gemfireProperties);
-    StartMemberUtils.addGemFirePropertyFile(commandLine, gemfirePropertiesPathname);
-    StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesPathname);
+    StartMemberUtils.addGemFirePropertyFile(commandLine, gemfirePropertiesFile);
+    StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesFile);
     StartMemberUtils.addGemFireSystemProperties(commandLine, gemfireProperties);
     StartMemberUtils.addJvmArgumentsAndOptions(commandLine, jvmArgsOpts);
 

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UserInputProperty.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UserInputProperty.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UserInputProperty.java
new file mode 100644
index 0000000..5169dab
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/UserInputProperty.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_CIPHERS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_TYPE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_TYPE;
+
+import org.apache.commons.lang.StringUtils;
+
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.security.SecurableCommunicationChannel;
+import org.apache.geode.management.internal.cli.shell.Gfsh;
+import org.apache.geode.management.internal.security.ResourceConstants;
+
+public class UserInputProperty {
+  public static UserInputProperty USERNAME =
+      new UserInputProperty(ResourceConstants.USER_NAME, "user", false);
+  public static UserInputProperty PASSWORD =
+      new UserInputProperty(ResourceConstants.PASSWORD, "password", "", true);
+  public static UserInputProperty KEYSTORE =
+      new UserInputProperty(SSL_KEYSTORE, "key-store", "", false);
+  public static UserInputProperty KEYSTORE_PASSWORD =
+      new UserInputProperty(SSL_KEYSTORE_PASSWORD, "key-store-password", "", true);
+  public static UserInputProperty KEYSTORE_TYPE =
+      new UserInputProperty(SSL_KEYSTORE_TYPE, "key-store-type", "JKS", false);
+  public static UserInputProperty TRUSTSTORE =
+      new UserInputProperty(SSL_TRUSTSTORE, "trust-store", "", false);
+  public static UserInputProperty TRUSTSTORE_PASSWORD =
+      new UserInputProperty(SSL_TRUSTSTORE_PASSWORD, "trust-store-password", "", true);
+  public static UserInputProperty TRUSTSTORE_TYPE =
+      new UserInputProperty(SSL_TRUSTSTORE_TYPE, "trust-store-type", "JKS", false);
+  public static UserInputProperty CIPHERS = new UserInputProperty(SSL_CIPHERS, "ssl-ciphers",
+      DistributionConfig.DEFAULT_SSL_CIPHERS, false);
+  public static UserInputProperty PROTOCOL = new UserInputProperty(SSL_PROTOCOLS, "ssl-protocols",
+      DistributionConfig.DEFAULT_SSL_PROTOCOLS, false);
+  public static UserInputProperty COMPONENT = new UserInputProperty(SSL_ENABLED_COMPONENTS,
+      "ssl-enabled-components", SecurableCommunicationChannel.ALL.getConstant(), false);
+
+  private final String key;
+  private final String prompt;
+  private final boolean isMasked;
+  private final String defaultValue;
+
+  // use this if this property does not allow an empty string and has no default value
+  UserInputProperty(String key, String prompt, boolean isMasked) {
+    this(key, prompt, null, isMasked);
+  }
+
+  // if you allow an empty string for this property, supply a default value of ""
+  UserInputProperty(String key, String prompt, String defaultValue, boolean isMasked) {
+    this.key = key;
+    this.prompt = prompt;
+    this.defaultValue = defaultValue;
+    this.isMasked = isMasked;
+  }
+
+  public String promptForAcceptableValue(Gfsh gfsh) {
+    if (gfsh.isQuietMode() || gfsh.isHeadlessMode()) {
+      return defaultValue == null ? "" : defaultValue;
+    }
+
+    String value = promptForUserInput(gfsh);
+
+    if (value.length() > 0) {
+      return value;
+    }
+
+    // when user input an empty string and a default value is supplied, return the default value
+    if (value.length() == 0 && defaultValue != null) {
+      return defaultValue;
+    }
+
+    // otherwise prompt till we get a non-empty value, only when this property has no default value
+    while (value.length() == 0) {
+      value = promptForUserInput(gfsh);
+    }
+    return value;
+  }
+
+  private String promptForUserInput(Gfsh gfsh) {
+    String promptText = (StringUtils.isBlank(defaultValue)) ? prompt + ": "
+        : prompt + "(default: " + defaultValue + ")" + ": ";
+    String value;
+
+    if (isMasked) {
+      value = gfsh.readPassword(promptText);
+    } else {
+      value = gfsh.readText(promptText);
+    }
+    // when gfsh is mocked or quiet mode, the above would return null
+    if (value == null) {
+      value = "";
+    }
+    return value;
+  }
+
+  public String getKey() {
+    return key;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
index 58c8ef7..7562005 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
@@ -544,9 +544,9 @@ public class CliStrings {
       "Network address of the Locator in the form: host[port].";
   public static final String CONNECT__URL = "url";
   public static final String CONNECT__DEFAULT_BASE_URL =
-      "http://localhost:" + DistributionConfig.DEFAULT_HTTP_SERVICE_PORT + "/gemfire/v1";
+      "http://localhost:" + DistributionConfig.DEFAULT_HTTP_SERVICE_PORT + "/geode-mgmt/v1";
   public static final String CONNECT__DEFAULT_SSL_BASE_URL =
-      "https://localhost:" + DistributionConfig.DEFAULT_HTTP_SERVICE_PORT + "/gemfire/v1";
+      "https://localhost:" + DistributionConfig.DEFAULT_HTTP_SERVICE_PORT + "/geode-mgmt/v1";
   public static final String CONNECT__URL__HELP =
       "Indicates the base URL to the Manager's HTTP service.  For example: 'http://<host>:<port>/gemfire/v1' Default is '"
           + CONNECT__DEFAULT_BASE_URL + "'";

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/Gfsh.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/Gfsh.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/Gfsh.java
index a69ce36..503c252 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/Gfsh.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/Gfsh.java
@@ -475,14 +475,14 @@ public class Gfsh extends JLineShell {
     return signalHandler;
   }
 
-  public String readPassword(String textToPrompt) throws IOException {
+  public String readPassword(String textToPrompt) {
     if (isHeadlessMode && isQuietMode())
       return null;
 
     return readWithMask(textToPrompt, '*');
   }
 
-  public String readText(String textToPrompt) throws IOException {
+  public String readText(String textToPrompt) {
     if (isHeadlessMode && isQuietMode())
       return null;
 
@@ -618,12 +618,20 @@ public class Gfsh extends JLineShell {
     return success;
   }
 
-  public String interact(String textToPrompt) throws IOException {
-    return reader.readLine(textToPrompt);
+  public String interact(String textToPrompt) {
+    try {
+      return reader.readLine(textToPrompt);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
   }
 
-  public String readWithMask(String textToPrompt, Character mask) throws IOException {
-    return reader.readLine(textToPrompt, mask);
+  public String readWithMask(String textToPrompt, Character mask) {
+    try {
+      return reader.readLine(textToPrompt, mask);
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/JmxOperationInvoker.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/JmxOperationInvoker.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/JmxOperationInvoker.java
index 7ae7c3b..5066496 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/JmxOperationInvoker.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/JmxOperationInvoker.java
@@ -17,35 +17,17 @@ package org.apache.geode.management.internal.cli.shell;
 import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_PREFIX;
 import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_PREFIX;
 
-import org.apache.commons.lang.StringUtils;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.util.ArrayUtils;
-import org.apache.geode.internal.util.IOUtils;
-import org.apache.geode.management.DistributedSystemMXBean;
-import org.apache.geode.management.MemberMXBean;
-import org.apache.geode.management.internal.MBeanJMXAdapter;
-import org.apache.geode.management.internal.ManagementConstants;
-import org.apache.geode.management.internal.cli.CliUtil;
-import org.apache.geode.management.internal.cli.CommandRequest;
-import org.apache.geode.management.internal.cli.LogWrapper;
-import org.apache.geode.management.internal.cli.commands.ShellCommands;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-
-import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.net.MalformedURLException;
-import java.net.URL;
 import java.text.MessageFormat;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
+
 import javax.management.AttributeNotFoundException;
 import javax.management.InstanceNotFoundException;
 import javax.management.JMX;
@@ -63,6 +45,18 @@ import javax.management.remote.JMXConnectorFactory;
 import javax.management.remote.JMXServiceURL;
 import javax.rmi.ssl.SslRMIClientSocketFactory;
 
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.admin.SSLConfig;
+import org.apache.geode.internal.net.SSLConfigurationFactory;
+import org.apache.geode.internal.security.SecurableCommunicationChannel;
+import org.apache.geode.internal.util.ArrayUtils;
+import org.apache.geode.management.DistributedSystemMXBean;
+import org.apache.geode.management.MemberMXBean;
+import org.apache.geode.management.internal.MBeanJMXAdapter;
+import org.apache.geode.management.internal.ManagementConstants;
+import org.apache.geode.management.internal.cli.CommandRequest;
+import org.apache.geode.management.internal.cli.LogWrapper;
+
 /**
  * OperationInvoker JMX Implementation
  * 
@@ -99,9 +93,8 @@ public class JmxOperationInvoker implements OperationInvoker {
 
   private int clusterId = CLUSTER_ID_WHEN_NOT_CONNECTED;
 
-  public JmxOperationInvoker(final String host, final int port, final String userName,
-      final String password, final Map<String, String> sslConfigProps,
-      String gfSecurityPropertiesPath) throws Exception {
+  public JmxOperationInvoker(final String host, final int port, Properties gfProperties)
+      throws Exception {
     final Set<String> propsToClear = new TreeSet<String>();
     try {
       this.managerHost = host;
@@ -112,36 +105,41 @@ public class JmxOperationInvoker implements OperationInvoker {
       final Map<String, Object> env = new HashMap<String, Object>();
 
       env.put(JMXConnectionListener.CHECK_PERIOD_PROP, JMXConnectionListener.CHECK_PERIOD);
+      env.put(JMXConnector.CREDENTIALS, gfProperties);
 
-      if (userName != null && userName.length() > 0) {
-        env.put(JMXConnector.CREDENTIALS, new String[] {userName, password});
-      }
-      Set<Entry<String, String>> entrySet = sslConfigProps.entrySet();
-      for (Iterator<Entry<String, String>> it = entrySet.iterator(); it.hasNext();) {
-        Entry<String, String> entry = it.next();
-        String key = entry.getKey();
-        String value = entry.getValue();
-        key = checkforSystemPropertyPrefix(key);
-        if ((key.equals(Gfsh.SSL_ENABLED_CIPHERS) || key.equals(Gfsh.SSL_ENABLED_PROTOCOLS))
-            && "any".equals(value)) {
-          continue;
-        }
-        System.setProperty(key, value);
-        propsToClear.add(key);
-      }
+      SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(gfProperties,
+          SecurableCommunicationChannel.JMX);
 
-      if (!sslConfigProps.isEmpty()) {
-        if (System.getProperty(Gfsh.SSL_KEYSTORE) != null
-            || System.getProperty(Gfsh.SSL_TRUSTSTORE) != null) {
-          // use ssl to connect
-          env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory());
+      if (sslConfig.isEnabled()) {
+        if (sslConfig.getKeystore() != null) {
+          System.setProperty(SSLConfigurationFactory.JAVAX_KEYSTORE, sslConfig.getKeystore());
+          propsToClear.add(SSLConfigurationFactory.JAVAX_KEYSTORE);
         }
-      }
-
-      // Check for JMX Credentials if empty put properties instance directly so that
-      // jmx management interceptor can read it for custom security properties
-      if (!env.containsKey(JMXConnector.CREDENTIALS)) {
-        env.put(JMXConnector.CREDENTIALS, readProperties(gfSecurityPropertiesPath));
+        if (sslConfig.getKeystorePassword() != null) {
+          System.setProperty(SSLConfigurationFactory.JAVAX_KEYSTORE_PASSWORD,
+              sslConfig.getKeystorePassword());
+          propsToClear.add(SSLConfigurationFactory.JAVAX_KEYSTORE_PASSWORD);
+        }
+        if (sslConfig.getKeystoreType() != null) {
+          System.setProperty(SSLConfigurationFactory.JAVAX_KEYSTORE_TYPE,
+              sslConfig.getKeystoreType());
+          propsToClear.add(SSLConfigurationFactory.JAVAX_KEYSTORE_TYPE);
+        }
+        if (sslConfig.getTruststore() != null) {
+          System.setProperty(SSLConfigurationFactory.JAVAX_TRUSTSTORE, sslConfig.getTruststore());
+          propsToClear.add(SSLConfigurationFactory.JAVAX_TRUSTSTORE);
+        }
+        if (sslConfig.getTruststorePassword() != null) {
+          System.setProperty(SSLConfigurationFactory.JAVAX_TRUSTSTORE_PASSWORD,
+              sslConfig.getTruststorePassword());
+          propsToClear.add(SSLConfigurationFactory.JAVAX_TRUSTSTORE_PASSWORD);
+        }
+        if (sslConfig.getTruststoreType() != null) {
+          System.setProperty(SSLConfigurationFactory.JAVAX_TRUSTSTORE_TYPE,
+              sslConfig.getTruststoreType());
+          propsToClear.add(SSLConfigurationFactory.JAVAX_TRUSTSTORE_TYPE);
+        }
+        env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory());
       }
 
       this.url = new JMXServiceURL(MessageFormat.format(JMX_URL_FORMAT,
@@ -184,57 +182,6 @@ public class JmxOperationInvoker implements OperationInvoker {
     }
   }
 
-  // Copied from ShellCommands.java
-  private Properties readProperties(String gfSecurityPropertiesPath) throws MalformedURLException {
-    Gfsh gfshInstance = Gfsh.getCurrentInstance();
-    // reference to hold resolved gfSecurityPropertiesPath
-    String gfSecurityPropertiesPathToUse = CliUtil.resolvePathname(gfSecurityPropertiesPath);
-    URL gfSecurityPropertiesUrl = null;
-
-    // Case 1: User has specified gfSecurity properties file
-    if (StringUtils.isNotBlank(gfSecurityPropertiesPathToUse)) {
-      // User specified gfSecurity properties doesn't exist
-      if (!IOUtils.isExistingPathname(gfSecurityPropertiesPathToUse)) {
-        gfshInstance
-            .printAsSevere(CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE,
-                "Security ", gfSecurityPropertiesPathToUse));
-      } else {
-        gfSecurityPropertiesUrl = new File(gfSecurityPropertiesPathToUse).toURI().toURL();
-      }
-    } else if (gfSecurityPropertiesPath == null) {
-      // Use default "gfsecurity.properties"
-      // in current dir, user's home or classpath
-      gfSecurityPropertiesUrl = ShellCommands.getFileUrl("gfsecurity.properties");
-    }
-    // if 'gfSecurityPropertiesPath' OR gfsecurity.properties has resolvable path
-    if (gfSecurityPropertiesUrl != null) {
-      gfshInstance.logToFile("Using security properties file : "
-          + CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath()), null);
-      return loadPropertiesFromURL(gfSecurityPropertiesUrl);
-    }
-    return null;
-  }
-
-  static Properties loadPropertiesFromURL(URL gfSecurityPropertiesUrl) {
-    Properties props = new Properties();
-    if (gfSecurityPropertiesUrl != null) {
-      InputStream inputStream = null;
-      try {
-
-        inputStream = gfSecurityPropertiesUrl.openStream();
-        props.load(inputStream);
-      } catch (IOException io) {
-        throw new RuntimeException(
-            CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_READ_CONFIG_FROM_0,
-                CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath())),
-            io);
-      } finally {
-        IOUtils.close(inputStream);
-      }
-    }
-    return props;
-  }
-
   private String checkforSystemPropertyPrefix(String key) {
     String returnKey = key;
     if (key.startsWith("javax.")) {

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/GfshConsoleReader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/GfshConsoleReader.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/GfshConsoleReader.java
index 9251d7e..a635c50 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/GfshConsoleReader.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/GfshConsoleReader.java
@@ -15,8 +15,6 @@
 
 package org.apache.geode.management.internal.cli.util;
 
-import java.io.IOException;
-
 import org.apache.geode.internal.GfeConsoleReaderFactory.GfeConsoleReader;
 import org.apache.geode.management.internal.cli.shell.Gfsh;
 
@@ -44,11 +42,7 @@ public class GfshConsoleReader extends GfeConsoleReader {
   public String readLine(String textToPrompt) {
     String lineRead = null;
     if (isSupported()) {
-      try {
-        lineRead = gfsh.interact(textToPrompt);
-      } catch (IOException e) {
-        lineRead = null;
-      }
+      lineRead = gfsh.interact(textToPrompt);
     }
     return lineRead;
   }
@@ -56,12 +50,8 @@ public class GfshConsoleReader extends GfeConsoleReader {
   public char[] readPassword(String textToPrompt) {
     char[] password = null;
     if (isSupported()) {
-      try {
-        String passwordString = gfsh.readWithMask(textToPrompt, '*');
-        password = passwordString.toCharArray();
-      } catch (IOException e) {
-        password = null;
-      }
+      String passwordString = gfsh.readWithMask(textToPrompt, '*');
+      password = passwordString.toCharArray();
     }
     return password;
   }

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/ClusterConfigurationStatusRetriever.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/ClusterConfigurationStatusRetriever.java b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/ClusterConfigurationStatusRetriever.java
index 3080809..86681b1 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/ClusterConfigurationStatusRetriever.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/configuration/utils/ClusterConfigurationStatusRetriever.java
@@ -14,6 +14,11 @@
  */
 package org.apache.geode.management.internal.configuration.utils;
 
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.Properties;
+import java.util.Set;
+
 import org.apache.geode.distributed.LocatorLauncher;
 import org.apache.geode.distributed.internal.tcpserver.TcpClient;
 import org.apache.geode.internal.cache.persistence.PersistentMemberPattern;
@@ -21,22 +26,17 @@ import org.apache.geode.management.internal.cli.shell.Gfsh;
 import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusRequest;
 import org.apache.geode.management.internal.configuration.messages.SharedConfigurationStatusResponse;
 
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.util.Set;
-
 public class ClusterConfigurationStatusRetriever {
   private static final int NUM_ATTEMPTS_FOR_SHARED_CONFIGURATION_STATUS = 3;
 
-  public static String fromLocator(String locatorHostName, int locatorPort)
+  public static String fromLocator(String locatorHostName, int locatorPort, Properties configProps)
       throws ClassNotFoundException, IOException {
     final StringBuilder buffer = new StringBuilder();
 
     try {
       final InetAddress networkAddress = InetAddress.getByName(locatorHostName);
 
-      TcpClient client = new TcpClient();
+      TcpClient client = new TcpClient(configProps);
       SharedConfigurationStatusResponse statusResponse =
           (SharedConfigurationStatusResponse) client.requestToServer(networkAddress, locatorPort,
               new SharedConfigurationStatusRequest(), 10000, true);
@@ -114,6 +114,7 @@ public class ClusterConfigurationStatusRetriever {
 
   public static String fromLocator(LocatorLauncher.LocatorState locatorState)
       throws ClassNotFoundException, IOException {
-    return fromLocator(locatorState.getHost(), Integer.parseInt(locatorState.getPort()));
+    return fromLocator(locatorState.getHost(), Integer.parseInt(locatorState.getPort()),
+        new Properties());
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigurationFactoryJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigurationFactoryJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigurationFactoryJUnitTest.java
index 31c2469..47f0d2b 100644
--- a/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigurationFactoryJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/internal/net/SSLConfigurationFactoryJUnitTest.java
@@ -32,22 +32,24 @@ import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTOR
 import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
 import static org.apache.geode.distributed.ConfigurationProperties.SSL_WEB_ALIAS;
 import static org.apache.geode.distributed.ConfigurationProperties.SSL_WEB_SERVICE_REQUIRE_AUTHENTICATION;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 
+import java.util.Properties;
+
 import org.apache.commons.lang.StringUtils;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.distributed.internal.DistributionConfigImpl;
-import org.apache.geode.internal.admin.SSLConfig;
-import org.apache.geode.internal.security.SecurableCommunicationChannel;
-import org.apache.geode.test.junit.categories.MembershipTest;
-import org.apache.geode.test.junit.categories.UnitTest;
 import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.contrib.java.lang.system.RestoreSystemProperties;
 import org.junit.experimental.categories.Category;
 
-import java.util.Properties;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.distributed.internal.DistributionConfigImpl;
+import org.apache.geode.internal.admin.SSLConfig;
+import org.apache.geode.internal.security.SecurableCommunicationChannel;
+import org.apache.geode.test.junit.categories.MembershipTest;
+import org.apache.geode.test.junit.categories.UnitTest;
 
 @Category({UnitTest.class, MembershipTest.class})
 public class SSLConfigurationFactoryJUnitTest {
@@ -280,6 +282,27 @@ public class SSLConfigurationFactoryJUnitTest {
     assertEquals(true, sslConfig.isEnabled());
   }
 
+  @Test
+  public void setDistributionConfig() throws Exception {
+    Properties properties = new Properties();
+    properties.setProperty(SSL_ENABLED_COMPONENTS, "all");
+    properties.setProperty(SSL_KEYSTORE, "someKeyStore");
+    DistributionConfigImpl distributionConfig = new DistributionConfigImpl(properties);
+    SSLConfigurationFactory.setDistributionConfig(distributionConfig);
+
+    SSLConfig sslConfig =
+        SSLConfigurationFactory.getSSLConfigForComponent(SecurableCommunicationChannel.LOCATOR);
+    assertThat(sslConfig.isEnabled()).isTrue();
+    assertThat(sslConfig.getKeystore()).isEqualTo("someKeyStore");
+
+    properties.setProperty(SSL_ENABLED_COMPONENTS, SecurableCommunicationChannel.JMX.getConstant());
+    properties.setProperty(SSL_KEYSTORE, "someOtherKeyStore");
+    sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(properties,
+        SecurableCommunicationChannel.LOCATOR);
+    assertThat(sslConfig.isEnabled()).isFalse();
+    assertThat(sslConfig.getKeystore()).isEqualTo("someOtherKeyStore");
+  }
+
   private void assertSSLConfig(final Properties properties, final SSLConfig sslConfig,
       final SecurableCommunicationChannel expectedSecurableComponent,
       final DistributionConfigImpl distributionConfig) {

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java
deleted file mode 100644
index 866f4ef..0000000
--- a/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorSSLDUnitTest.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.management;
-
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_CIPHERS;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
-import static org.apache.geode.util.test.TestUtil.getResourcePath;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.util.Properties;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.RuleChain;
-import org.junit.rules.TemporaryFolder;
-
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.security.SecurableCommunicationChannels;
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.rules.CleanupDUnitVMsRule;
-import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
-import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
-import org.apache.geode.test.dunit.rules.MemberVM;
-import org.apache.geode.test.junit.categories.DistributedTest;
-import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
-
-@Category(DistributedTest.class)
-public class ConnectToLocatorSSLDUnitTest {
-  private TemporaryFolder folder = new SerializableTemporaryFolder();
-  private LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
-  private CleanupDUnitVMsRule cleanupDUnitVMsRule = new CleanupDUnitVMsRule();
-
-  @Rule
-  public RuleChain ruleChain =
-      RuleChain.outerRule(folder).around(cleanupDUnitVMsRule).around(lsRule);
-
-  private File jks = null;
-  protected File securityPropsFile = null;
-  private Properties securityProps;
-  protected MemberVM locator;
-
-  @Before
-  public void before() throws Exception {
-    jks = new File(getResourcePath(getClass(), "/ssl/trusted.keystore"));
-    securityPropsFile = folder.newFile("security.properties");
-    securityProps = new Properties();
-  }
-
-  protected void connect() throws Exception {
-    final int locatorPort = locator.getPort();
-    final String securityPropsFilePath = securityPropsFile.getCanonicalPath();
-
-    // when gfsh uses SSL, it leaves SSL state behind to contaminate other tests. So we pushed
-    // gfsh into a VM and uses a CleanupDUnitVM rule to clean it up after each test.
-    Host.getHost(0).getVM(1).invoke(() -> {
-      GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
-      gfshConnector.connectAndVerify(locatorPort, GfshShellConnectionRule.PortType.locator,
-          CliStrings.CONNECT__SECURITY_PROPERTIES, securityPropsFilePath);
-      gfshConnector.executeAndVerifyCommand("list members");
-      gfshConnector.close();
-    });
-
-  }
-
-  @Test
-  public void testConnectToLocator_withSSL() throws Exception {
-    securityProps.setProperty(SSL_ENABLED_COMPONENTS, SecurableCommunicationChannels.ALL);
-    securityProps.setProperty(SSL_KEYSTORE, jks.getCanonicalPath());
-    securityProps.setProperty(SSL_KEYSTORE_PASSWORD, "password");
-    securityProps.setProperty(SSL_TRUSTSTORE, jks.getCanonicalPath());
-    securityProps.setProperty(SSL_TRUSTSTORE_PASSWORD, "password");
-    securityProps.setProperty(SSL_PROTOCOLS, "TLSv1.2");
-    securityProps.setProperty(SSL_CIPHERS, "any");
-
-    // start up the locator
-    locator = lsRule.startLocatorVM(0, securityProps);
-    // saving the securityProps to a file
-    OutputStream out = new FileOutputStream(securityPropsFile);
-    securityProps.store(out, null);
-
-    connect();
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorWithLegacySSLDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorWithLegacySSLDUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorWithLegacySSLDUnitTest.java
deleted file mode 100644
index d7db489..0000000
--- a/geode-core/src/test/java/org/apache/geode/management/ConnectToLocatorWithLegacySSLDUnitTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.management;
-
-import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_ENABLED;
-import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE_PASSWORD;
-import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE_TYPE;
-import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_TRUSTSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_TRUSTSTORE_PASSWORD;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_ENABLED;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE_PASSWORD;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE_TYPE;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_TRUSTSTORE;
-import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_TRUSTSTORE_PASSWORD;
-import static org.apache.geode.util.test.TestUtil.getResourcePath;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.util.Properties;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.RuleChain;
-import org.junit.rules.TemporaryFolder;
-
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.rules.CleanupDUnitVMsRule;
-import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
-import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
-import org.apache.geode.test.dunit.rules.MemberVM;
-import org.apache.geode.test.junit.categories.DistributedTest;
-import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
-
-@Category(DistributedTest.class)
-public class ConnectToLocatorWithLegacySSLDUnitTest {
-  private TemporaryFolder folder = new SerializableTemporaryFolder();
-  private LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
-  private CleanupDUnitVMsRule cleanupDUnitVMsRule = new CleanupDUnitVMsRule();
-
-  @Rule
-  public RuleChain ruleChain =
-      RuleChain.outerRule(folder).around(cleanupDUnitVMsRule).around(lsRule);
-
-  private File jks = null;
-  protected File securityPropsFile = null;
-  private Properties securityProps;
-  protected MemberVM locator;
-
-  @Before
-  public void before() throws Exception {
-    jks = new File(getResourcePath(getClass(), "/ssl/trusted.keystore"));
-    securityPropsFile = folder.newFile("security.properties");
-    securityProps = new Properties();
-  }
-
-  protected void startUpLocatorAndConnect(Properties properties) throws Exception {
-    locator = lsRule.startLocatorVM(0, securityProps);
-    // saving the securityProps to a file
-    OutputStream out = new FileOutputStream(securityPropsFile);
-    securityProps.store(out, null);
-
-    final int locatorPort = locator.getPort();
-    final String securityPropsFilePath = securityPropsFile.getCanonicalPath();
-
-    // when gfsh uses SSL, it leaves SSL state behind to contaminate other tests. So we pushed
-    // gfsh into a VM and uses a CleanupDUnitVM rule to clean it up after each test.
-    Host.getHost(0).getVM(1).invoke(() -> {
-      GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
-      gfshConnector.connectAndVerify(locatorPort, GfshShellConnectionRule.PortType.locator,
-          CliStrings.CONNECT__SECURITY_PROPERTIES, securityPropsFilePath);
-      gfshConnector.executeAndVerifyCommand("list members");
-      gfshConnector.close();
-    });
-  }
-
-  @Test
-  public void testConnectToLocator_withLegacyClusterSSL() throws Exception {
-    securityProps.setProperty(CLUSTER_SSL_ENABLED, "true");
-    securityProps.setProperty(CLUSTER_SSL_KEYSTORE, jks.getCanonicalPath());
-    securityProps.setProperty(CLUSTER_SSL_KEYSTORE_PASSWORD, "password");
-    securityProps.setProperty(CLUSTER_SSL_KEYSTORE_TYPE, "JKS");
-    securityProps.setProperty(CLUSTER_SSL_TRUSTSTORE, jks.getCanonicalPath());
-    securityProps.setProperty(CLUSTER_SSL_TRUSTSTORE_PASSWORD, "password");
-
-    startUpLocatorAndConnect(securityProps);
-  }
-
-  @Test
-  public void testConnectToLocator_withLegacyJMXManagerSSL() throws Exception {
-    securityProps.setProperty(JMX_MANAGER_SSL_ENABLED, "true");
-    securityProps.setProperty(JMX_MANAGER_SSL_KEYSTORE, jks.getCanonicalPath());
-    securityProps.setProperty(JMX_MANAGER_SSL_KEYSTORE_PASSWORD, "password");
-    securityProps.setProperty(JMX_MANAGER_SSL_KEYSTORE_TYPE, "JKS");
-    securityProps.setProperty(JMX_MANAGER_SSL_TRUSTSTORE, jks.getCanonicalPath());
-    securityProps.setProperty(JMX_MANAGER_SSL_TRUSTSTORE_PASSWORD, "password");
-
-    startUpLocatorAndConnect(securityProps);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserConverterTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserConverterTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserConverterTest.java
index 3c42e0b..1ad22d4 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserConverterTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/GfshParserConverterTest.java
@@ -17,7 +17,16 @@ package org.apache.geode.management.internal.cli;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.springframework.shell.event.ParseResult;
 
 import org.apache.geode.management.internal.cli.converters.DiskStoreNameConverter;
 import org.apache.geode.management.internal.cli.converters.FilePathConverter;
@@ -25,15 +34,6 @@ import org.apache.geode.management.internal.cli.converters.FilePathStringConvert
 import org.apache.geode.management.internal.cli.converters.RegionPathConverter;
 import org.apache.geode.test.dunit.rules.GfshParserRule;
 import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.springframework.shell.event.ParseResult;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
 
 @Category(IntegrationTest.class)
 public class GfshParserConverterTest {
@@ -152,12 +152,12 @@ public class GfshParserConverterTest {
     doReturn(roots).when(spy).getRoots();
     doReturn(siblings).when(spy).getSiblings(any());
 
-    String command = "start server --properties-file=";
+    String command = "start server --cache-xml-file=";
     commandCandidate = parser.complete(command);
     assertThat(commandCandidate.size()).isEqualTo(2);
     assertThat(commandCandidate.getFirstCandidate()).isEqualTo(command + "/logs");
 
-    command = "start server --properties-file=sibling";
+    command = "start server --cache-xml-file=sibling";
     commandCandidate = parser.complete(command);
     assertThat(commandCandidate.size()).isEqualTo(2);
     assertThat(commandCandidate.getFirstCandidate()).isEqualTo(command + "1");
@@ -170,6 +170,7 @@ public class GfshParserConverterTest {
     assertThat(commandCandidate.getFirstCandidate()).isEqualTo(command + "1");
   }
 
+
   @Test
   public void testRegionPathConverter() throws Exception {
     RegionPathConverter spy = parser.spyConverter(RegionPathConverter.class);

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandTest.java
new file mode 100644
index 0000000..3a5c584
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandTest.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.util.Properties;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.mockito.ArgumentCaptor;
+
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.CommandResult;
+import org.apache.geode.management.internal.cli.shell.Gfsh;
+import org.apache.geode.management.internal.cli.shell.OperationInvoker;
+import org.apache.geode.test.dunit.rules.GfshParserRule;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class ConnectCommandTest {
+
+  @ClassRule
+  public static GfshParserRule gfshParserRule = new GfshParserRule();
+
+  private ConnectCommand connectCommand;
+
+  private Gfsh gfsh = mock(Gfsh.class);
+
+  private CommandResult result;
+  private Properties properties;
+  private ArgumentCaptor<File> fileCaptor;
+
+  @Before
+  public void before() throws Exception {
+    properties = new Properties();
+    when(gfsh.getOperationInvoker()).thenReturn(mock(OperationInvoker.class));
+    // using spy instead of mock because we want to call the real method when we do connect
+    connectCommand = spy(ConnectCommand.class);
+    when(connectCommand.getGfsh()).thenReturn(gfsh);
+    doReturn(properties).when(connectCommand).loadProperties(any());
+    CommandResult result = mock(CommandResult.class);
+    when(connectCommand.httpConnect(any(), any())).thenReturn(result);
+    when(connectCommand.jmxConnect(any(), anyBoolean(), any(), any(), anyBoolean()))
+        .thenReturn(result);
+    fileCaptor = ArgumentCaptor.forClass(File.class);
+  }
+
+  @Test
+  public void whenGfshIsAlreadyConnected() throws Exception {
+    when(gfsh.isConnectedAndReady()).thenReturn(true);
+    result = gfshParserRule.executeCommandWithInstance(connectCommand, "connect");
+    assertThat(result.nextLine()).contains("Already connected to");
+  }
+
+  @Test
+  public void promptForPasswordIfUsernameIsGiven() throws Exception {
+    doReturn(properties).when(connectCommand).resolveSslProperties(any(), anyBoolean(), any(),
+        any());
+    result = gfshParserRule.executeCommandWithInstance(connectCommand, "connect --user=user");
+    verify(gfsh).readPassword(CliStrings.CONNECT__PASSWORD + ": ");
+
+    assertThat(properties.getProperty("security-username")).isEqualTo("user");
+    assertThat(properties.getProperty("security-password")).isEqualTo("");
+  }
+
+  @Test
+  public void notPromptForPasswordIfUsernameIsGiven() throws Exception {
+    doReturn(properties).when(connectCommand).resolveSslProperties(any(), anyBoolean(), any(),
+        any());
+    result = gfshParserRule.executeCommandWithInstance(connectCommand,
+        "connect --user=user --password=pass");
+    verify(gfsh, times(0)).readPassword(CliStrings.CONNECT__PASSWORD + ": ");
+
+    assertThat(properties.getProperty("security-username")).isEqualTo("user");
+    assertThat(properties.getProperty("security-password")).isEqualTo("pass");
+  }
+
+  @Test
+  public void notPromptForPasswordIfuserNameisGivenInFile() throws Exception {
+    // username specified in property file won't promot for password
+    properties.setProperty("security-username", "user");
+    doReturn(properties).when(connectCommand).loadProperties(any(File.class));
+
+    result = gfshParserRule.executeCommandWithInstance(connectCommand, "connect");
+    verify(gfsh, times(0)).readPassword(CliStrings.CONNECT__PASSWORD + ": ");
+
+    assertThat(properties).doesNotContainKey("security-password");
+  }
+
+  @Test
+  public void plainConnectNotLoadFileNotPrompt() throws Exception {
+    result = gfshParserRule.executeCommandWithInstance(connectCommand, "connect");
+    // will not try to load from any file
+    verify(connectCommand).loadProperties(null, null);
+
+    // will not try to prompt
+    verify(gfsh, times(0)).readText(any());
+    verify(gfsh, times(0)).readPassword(any());
+  }
+
+  @Test
+  public void connectUseSsl() throws Exception {
+    result = gfshParserRule.executeCommandWithInstance(connectCommand, "connect --use-ssl");
+
+    // will not try to load from any file
+    verify(connectCommand).loadProperties(null, null);
+
+    // gfsh will prompt for the all the ssl properties
+    verify(gfsh).readText("key-store: ");
+    verify(gfsh).readPassword("key-store-password: ");
+    verify(gfsh).readText("key-store-type(default: JKS): ");
+    verify(gfsh).readText("trust-store: ");
+    verify(gfsh).readPassword("trust-store-password: ");
+    verify(gfsh).readText("trust-store-type(default: JKS): ");
+    verify(gfsh).readText("ssl-ciphers(default: any): ");
+    verify(gfsh).readText("ssl-protocols(default: any): ");
+
+    // verify the resulting properties has correct values
+    assertThat(properties).hasSize(9);
+    assertThat(properties.getProperty("ssl-keystore")).isEqualTo("");
+    assertThat(properties.getProperty("ssl-keystore-password")).isEqualTo("");
+    assertThat(properties.getProperty("ssl-keystore-type")).isEqualTo("JKS");
+    assertThat(properties.getProperty("ssl-truststore")).isEqualTo("");
+    assertThat(properties.getProperty("ssl-truststore-password")).isEqualTo("");
+    assertThat(properties.getProperty("ssl-truststore-type")).isEqualTo("JKS");
+    assertThat(properties.getProperty("ssl-ciphers")).isEqualTo("any");
+    assertThat(properties.getProperty("ssl-protocols")).isEqualTo("any");
+    assertThat(properties.getProperty("ssl-enabled-components")).isEqualTo("all");
+  }
+
+  @Test
+  public void securityFileContainsSSLPropsAndNoUseSSL() throws Exception {
+    properties.setProperty(SSL_KEYSTORE, "keystore");
+    result = gfshParserRule.executeCommandWithInstance(connectCommand,
+        "connect --security-properties-file=test");
+
+    // will try to load from this file
+    verify(connectCommand).loadProperties(any(), fileCaptor.capture());
+    assertThat(fileCaptor.getValue()).hasName("test");
+
+    // it will prompt for missing properties
+    verify(gfsh, times(6)).readText(any());
+    verify(gfsh, times(2)).readPassword(any());
+  }
+
+  @Test
+  public void securityFileContainsNoSSLPropsAndNoUseSSL() throws Exception {
+    result = gfshParserRule.executeCommandWithInstance(connectCommand,
+        "connect --security-properties-file=test");
+
+    // will try to load from this file
+    verify(connectCommand).loadProperties(any(), fileCaptor.capture());
+    assertThat(fileCaptor.getValue()).hasName("test");
+
+    // it will prompt for missing properties
+    verify(gfsh, times(0)).readText(any());
+    verify(gfsh, times(0)).readPassword(any());
+  }
+
+  @Test
+  public void connectUseLegacySecurityPropertiesFile() throws Exception {
+    properties.setProperty(JMX_MANAGER_SSL_KEYSTORE, "jmx-keystore");
+    result = gfshParserRule.executeCommandWithInstance(connectCommand,
+        "connect --security-properties-file=test --key-store=keystore --key-store-password=password");
+
+    // wil try to load from this file
+    verify(connectCommand).loadProperties(fileCaptor.capture());
+    assertThat(fileCaptor.getValue()).hasName("test");
+
+    // it will not prompt for missing properties
+    verify(gfsh, times(0)).readText(any());
+    verify(gfsh, times(0)).readPassword(any());
+
+    // the command option will be ignored
+    assertThat(properties).hasSize(1);
+    assertThat(properties.get(JMX_MANAGER_SSL_KEYSTORE)).isEqualTo("jmx-keystore");
+  }
+
+  @Test
+  public void connectUseSecurityPropertiesFile_promptForMissing() throws Exception {
+    properties.setProperty(SSL_KEYSTORE, "keystore");
+    properties.setProperty(SSL_KEYSTORE_PASSWORD, "password");
+    result = gfshParserRule.executeCommandWithInstance(connectCommand,
+        "connect --security-properties-file=test");
+
+    // since nothing is loaded, will prompt for all missing values
+    verify(gfsh, times(6)).readText(any());
+    verify(gfsh, times(1)).readPassword(any());
+  }
+
+  @Test
+  public void connectUseSecurityPropertiesFileAndOption_promptForMissing() throws Exception {
+    properties.setProperty(SSL_KEYSTORE, "keystore");
+    properties.setProperty(SSL_KEYSTORE_PASSWORD, "password");
+    result = gfshParserRule.executeCommandWithInstance(connectCommand,
+        "connect --security-properties-file=test --key-store=keystore2 --trust-store=truststore2");
+
+    // since nothing is loaded, will prompt for all missing values
+    verify(gfsh, times(5)).readText(any());
+    verify(gfsh, times(1)).readPassword(any());
+
+    assertThat(properties).hasSize(9);
+    assertThat(properties.getProperty("ssl-keystore")).isEqualTo("keystore2");
+    assertThat(properties.getProperty("ssl-keystore-password")).isEqualTo("password");
+    assertThat(properties.getProperty("ssl-keystore-type")).isEqualTo("JKS");
+    assertThat(properties.getProperty("ssl-truststore")).isEqualTo("truststore2");
+    assertThat(properties.getProperty("ssl-truststore-password")).isEqualTo("");
+    assertThat(properties.getProperty("ssl-truststore-type")).isEqualTo("JKS");
+    assertThat(properties.getProperty("ssl-ciphers")).isEqualTo("any");
+    assertThat(properties.getProperty("ssl-protocols")).isEqualTo("any");
+    assertThat(properties.getProperty("ssl-enabled-components")).isEqualTo("all");
+  }
+
+  @Test
+  public void containsLegacySSLConfigTest_ssl() throws Exception {
+    properties.setProperty(SSL_KEYSTORE, "keystore");
+    assertThat(connectCommand.containsLegacySSLConfig(properties)).isFalse();
+  }
+
+  @Test
+  public void containsLegacySSLConfigTest_cluster() throws Exception {
+    properties.setProperty(CLUSTER_SSL_KEYSTORE, "cluster-keystore");
+    assertThat(connectCommand.containsLegacySSLConfig(properties)).isTrue();
+  }
+
+  @Test
+  public void containsLegacySSLConfigTest_jmx() throws Exception {
+    properties.setProperty(JMX_MANAGER_SSL_KEYSTORE, "jmx-keystore");
+    assertThat(connectCommand.containsLegacySSLConfig(properties)).isTrue();
+  }
+
+  @Test
+  public void containsLegacySSLConfigTest_http() throws Exception {
+    properties.setProperty(HTTP_SERVICE_SSL_KEYSTORE, "http-keystore");
+    assertThat(connectCommand.containsLegacySSLConfig(properties)).isTrue();
+  }
+
+  @Test
+  public void loadPropertiesWithNull() throws Exception {
+    doCallRealMethod().when(connectCommand).loadProperties(any());
+    assertThat(connectCommand.loadProperties(null, null)).isEmpty();
+  }
+
+  @Test
+  public void isSslImpliedByOptions() throws Exception {
+    assertThat(connectCommand.isSslImpliedBySslOptions(null)).isFalse();
+
+    assertThat(connectCommand.isSslImpliedBySslOptions(null, null, null)).isFalse();
+
+    assertThat(connectCommand.isSslImpliedBySslOptions(null, "test")).isTrue();
+  }
+
+  @Test
+  public void resolveSslProperties() throws Exception {
+    // assume properties loaded from either file has an ssl property
+    properties.setProperty(SSL_KEYSTORE, "keystore");
+    properties = connectCommand.resolveSslProperties(gfsh, false, null, null);
+    assertThat(properties).hasSize(9);
+
+    properties.clear();
+
+    properties.setProperty(SSL_KEYSTORE, "keystore");
+    properties =
+        connectCommand.resolveSslProperties(gfsh, false, null, null, "keystore2", "password");
+    assertThat(properties).hasSize(9);
+    assertThat(properties.getProperty(SSL_KEYSTORE)).isEqualTo("keystore2");
+    assertThat(properties.getProperty(SSL_KEYSTORE_PASSWORD)).isEqualTo("password");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
index 67c3f5a..da60c7a 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/GfshCommandJUnitTest.java
@@ -29,6 +29,24 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
+import java.io.File;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.jmock.lib.concurrent.Synchroniser;
+import org.jmock.lib.legacy.ClassImposteriser;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
 import org.apache.geode.cache.execute.Function;
 import org.apache.geode.cache.execute.FunctionService;
 import org.apache.geode.distributed.DistributedMember;
@@ -41,23 +59,6 @@ import org.apache.geode.management.cli.CliMetaData;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.util.MemberNotFoundException;
 import org.apache.geode.test.junit.categories.UnitTest;
-import org.jmock.Expectations;
-import org.jmock.Mockery;
-import org.jmock.lib.concurrent.Synchroniser;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import java.io.File;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
 
 /**
  * The GfshCommandJUnitTest class is a test suite of test cases testing the contract and
@@ -412,11 +413,7 @@ public class GfshCommandJUnitTest {
     assertTrue(commandLine.isEmpty());
     StartMemberUtils.addGemFirePropertyFile(commandLine, null);
     assertTrue(commandLine.isEmpty());
-    StartMemberUtils.addGemFirePropertyFile(commandLine, org.apache.commons.lang.StringUtils.EMPTY);
-    assertTrue(commandLine.isEmpty());
-    StartMemberUtils.addGemFirePropertyFile(commandLine, " ");
-    assertTrue(commandLine.isEmpty());
-    StartMemberUtils.addGemFirePropertyFile(commandLine, "/path/to/gemfire.properties");
+    StartMemberUtils.addGemFirePropertyFile(commandLine, new File("/path/to/gemfire.properties"));
     assertFalse(commandLine.isEmpty());
     assertTrue(commandLine.contains("-DgemfirePropertyFile=/path/to/gemfire.properties"));
   }

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserInputPropertyTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserInputPropertyTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserInputPropertyTest.java
new file mode 100644
index 0000000..3527afd
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/UserInputPropertyTest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.management.internal.cli.shell.Gfsh;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class UserInputPropertyTest {
+
+  private UserInputProperty userInputProperty;
+  private Gfsh gfsh;
+
+  @Before
+  public void setUp() throws Exception {
+    gfsh = mock(Gfsh.class);
+  }
+
+  @Test
+  public void propertyWithNoDefaultVaueWillPromptTillAValueIsSupplied_interactive()
+      throws Exception {
+    userInputProperty = new UserInputProperty("key", "prompt", false);
+
+    when(gfsh.readText(any())).thenReturn("").thenReturn("").thenReturn("value");
+    String input = userInputProperty.promptForAcceptableValue(gfsh);
+
+    assertThat(input).isEqualTo("value");
+    verify(gfsh, times(0)).readPassword(any());
+    verify(gfsh, times(3)).readText(any());
+  }
+
+  @Test
+  public void propertyWithNoDefaultValue_quietMode() throws Exception {
+    when(gfsh.isQuietMode()).thenReturn(true);
+    userInputProperty = new UserInputProperty("key", "prompt", false);
+    String input = userInputProperty.promptForAcceptableValue(gfsh);
+    assertThat(input).isEqualTo("");
+    verify(gfsh, times(0)).readPassword(any());
+    verify(gfsh, times(0)).readText(any());
+  }
+
+  @Test
+  public void propertyWithDefaultValue_Interactive() throws Exception {
+    userInputProperty = new UserInputProperty("key", "prompt", "value", false);
+    String input = userInputProperty.promptForAcceptableValue(gfsh);
+    assertThat(input).isEqualTo("value");
+    verify(gfsh, times(0)).readPassword(any());
+    verify(gfsh).readText(any());
+  }
+
+  @Test
+  public void propertyWithEmptyDefaultValue_Interactive() throws Exception {
+    userInputProperty = new UserInputProperty("key", "prompt", "", false);
+    String input = userInputProperty.promptForAcceptableValue(gfsh);
+    assertThat(input).isEqualTo("");
+    verify(gfsh, times(0)).readPassword(any());
+    verify(gfsh).readText(any());
+  }
+
+  @Test
+  public void propertyWithDefaultValue_Interactive_masked() throws Exception {
+    userInputProperty = new UserInputProperty("key", "prompt", "value", true);
+    String input = userInputProperty.promptForAcceptableValue(gfsh);
+    assertThat(input).isEqualTo("value");
+    verify(gfsh).readPassword(any());
+    verify(gfsh, times(0)).readText(any());
+  }
+
+  @Test
+  public void propertyWithDefaultValue_Quiet() throws Exception {
+    when(gfsh.isQuietMode()).thenReturn(true);
+    userInputProperty = new UserInputProperty("key", "prompt", "value", false);
+    String input = userInputProperty.promptForAcceptableValue(gfsh);
+    assertThat(input).isEqualTo("value");
+    verify(gfsh, times(0)).readPassword(any());
+    verify(gfsh, times(0)).readText(any());
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-cq/src/test/java/org/apache/geode/management/CacheServerManagementDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-cq/src/test/java/org/apache/geode/management/CacheServerManagementDUnitTest.java b/geode-cq/src/test/java/org/apache/geode/management/CacheServerManagementDUnitTest.java
index 2cd69dd..a8d3997 100644
--- a/geode-cq/src/test/java/org/apache/geode/management/CacheServerManagementDUnitTest.java
+++ b/geode-cq/src/test/java/org/apache/geode/management/CacheServerManagementDUnitTest.java
@@ -14,17 +14,41 @@
  */
 package org.apache.geode.management;
 
-import org.junit.Ignore;
-import org.junit.experimental.categories.Category;
-import org.junit.Test;
+import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_HTTP_PORT;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-import static org.junit.Assert.*;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Properties;
 
-import org.apache.geode.test.junit.categories.DistributedTest;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.client.internal.LocatorTestBase;
-import org.apache.geode.cache.query.*;
+import org.apache.geode.cache.query.IndexExistsException;
+import org.apache.geode.cache.query.IndexInvalidException;
+import org.apache.geode.cache.query.IndexNameConflictException;
+import org.apache.geode.cache.query.QueryService;
+import org.apache.geode.cache.query.RegionNotFoundException;
 import org.apache.geode.cache.query.cq.dunit.CqQueryDUnitTest;
 import org.apache.geode.cache.query.internal.cq.CqService;
 import org.apache.geode.cache.server.CacheServer;
@@ -36,17 +60,15 @@ import org.apache.geode.internal.cache.GemFireCacheImpl;
 import org.apache.geode.management.internal.JmxManagerLocatorRequest;
 import org.apache.geode.management.internal.MBeanJMXAdapter;
 import org.apache.geode.management.internal.SystemManagementService;
-import org.apache.geode.test.dunit.*;
-
-import javax.management.*;
-import java.io.File;
-import java.io.IOException;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Collections;
-import java.util.Properties;
-
-import static org.apache.geode.distributed.ConfigurationProperties.*;
+import org.apache.geode.test.dunit.Assert;
+import org.apache.geode.test.dunit.Host;
+import org.apache.geode.test.dunit.LogWriterUtils;
+import org.apache.geode.test.dunit.NetworkUtils;
+import org.apache.geode.test.dunit.SerializableRunnable;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.dunit.Wait;
+import org.apache.geode.test.dunit.WaitCriterion;
+import org.apache.geode.test.junit.categories.DistributedTest;
 
 /**
  * Cache Server related management test cases
@@ -219,7 +241,7 @@ public class CacheServerManagementDUnitTest extends LocatorTestBase {
 
     // Step 4:
     JmxManagerLocatorRequest.send(locator.getHost().getHostName(), locatorPort,
-        CONNECT_LOCATOR_TIMEOUT_MS, Collections.<String, String>emptyMap());
+        CONNECT_LOCATOR_TIMEOUT_MS, new Properties());
 
     // Step 5:
     locator.invoke("Check locator", () -> {

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandIntegrationTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandIntegrationTest.java
new file mode 100644
index 0000000..bead33d
--- /dev/null
+++ b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandIntegrationTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
+import org.apache.geode.test.dunit.rules.LocatorStarterRule;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class ConnectCommandIntegrationTest {
+
+  @ClassRule
+  public static LocatorStarterRule locator = new LocatorStarterRule().withAutoStart();
+
+  @Rule
+  public GfshShellConnectionRule gfsh = new GfshShellConnectionRule();
+
+  @Test
+  public void connectToLocator() throws Exception {
+    gfsh.connectAndVerify(locator);
+  }
+
+  @Test
+  public void connectOverJmx() throws Exception {
+    gfsh.connectAndVerify(locator.getJmxPort(), GfshShellConnectionRule.PortType.jmxManger);
+  }
+
+  @Test
+  public void connectOverHttp() throws Exception {
+    gfsh.connectAndVerify(locator.getHttpPort(), GfshShellConnectionRule.PortType.http);
+  }
+}


[02/23] geode git commit: GEODE-3111 GatewayReceiver - DEFAULT_MANUAL_START value is ambiguous This closes #705

Posted by zh...@apache.org.
GEODE-3111 GatewayReceiver - DEFAULT_MANUAL_START value is ambiguous
This closes #705


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/08154dd7
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/08154dd7
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/08154dd7

Branch: refs/heads/feature/GEODE-3304
Commit: 08154dd7731910803aa5eb2caf0e284b3a239755
Parents: 06b839c
Author: Dave Barnes <db...@pivotal.io>
Authored: Wed Aug 9 16:17:14 2017 -0700
Committer: Dave Barnes <db...@pivotal.io>
Committed: Thu Aug 10 09:42:39 2017 -0700

----------------------------------------------------------------------
 .../apache/geode/cache/wan/GatewayReceiver.java |  2 +-
 .../gfsh/command-pages/create.html.md.erb       |  4 +--
 .../setting_up_a_multisite_system.html.md.erb   | 32 ++++++--------------
 .../multisite_overview.html.md.erb              |  3 +-
 4 files changed, 15 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/08154dd7/geode-core/src/main/java/org/apache/geode/cache/wan/GatewayReceiver.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/cache/wan/GatewayReceiver.java b/geode-core/src/main/java/org/apache/geode/cache/wan/GatewayReceiver.java
index 8c02af1..fd6f039 100644
--- a/geode-core/src/main/java/org/apache/geode/cache/wan/GatewayReceiver.java
+++ b/geode-core/src/main/java/org/apache/geode/cache/wan/GatewayReceiver.java
@@ -64,7 +64,7 @@ public interface GatewayReceiver {
   public static final String DEFAULT_HOSTNAME_FOR_SENDERS = "";
 
   /**
-   * The default value (true) for manually starting a <code>GatewayReceiver</code>.
+   * The default value for manually starting a <code>GatewayReceiver</code>.
    * 
    * @since GemFire 8.1
    */

http://git-wip-us.apache.org/repos/asf/geode/blob/08154dd7/geode-docs/tools_modules/gfsh/command-pages/create.html.md.erb
----------------------------------------------------------------------
diff --git a/geode-docs/tools_modules/gfsh/command-pages/create.html.md.erb b/geode-docs/tools_modules/gfsh/command-pages/create.html.md.erb
index b23ca56..01efcd8 100644
--- a/geode-docs/tools_modules/gfsh/command-pages/create.html.md.erb
+++ b/geode-docs/tools_modules/gfsh/command-pages/create.html.md.erb
@@ -392,7 +392,7 @@ create gateway-receiver [--group=value(,value)*] [--member=value(,value)*]
 </tr>
 <tr class="odd">
 <td><span class="keyword parmname">\-\-manual-start</span></td>
-<td>Boolean value that specifies whether you need to manually start the gateway receiver. If you supply a null value, the default is &quot;true&quot; and you will need to start the gateway receiver manually.</td>
+<td>Boolean value that specifies whether you need to manually start the gateway receiver. If you supply a null value, the default is &quot;false&quot; the gateway receiver starts automatically.</td>
 <td>true</td>
 </tr>
 <tr class="even">
@@ -517,7 +517,7 @@ create gateway-sender --id=value --remote-distributed-system-id=value
 </tr>
 <tr class="odd">
 <td><span class="keyword parmname">\-\-manual-start</span></td>
-<td>Boolean value that specifies whether you need to manually start the gateway sender. If you supply a null value, the default is &quot;false&quot; and the gateway sender attempts to start automatically.</td>
+<td>Boolean value that specifies whether you need to manually start the gateway sender. If you supply a null value, the default is &quot;false&quot; and the gateway sender starts automatically.</td>
 <td>false</td>
 </tr>
 <tr class="even">

http://git-wip-us.apache.org/repos/asf/geode/blob/08154dd7/geode-docs/topologies_and_comm/multi_site_configuration/setting_up_a_multisite_system.html.md.erb
----------------------------------------------------------------------
diff --git a/geode-docs/topologies_and_comm/multi_site_configuration/setting_up_a_multisite_system.html.md.erb b/geode-docs/topologies_and_comm/multi_site_configuration/setting_up_a_multisite_system.html.md.erb
index 0b5091d..dd2bc3a 100644
--- a/geode-docs/topologies_and_comm/multi_site_configuration/setting_up_a_multisite_system.html.md.erb
+++ b/geode-docs/topologies_and_comm/multi_site_configuration/setting_up_a_multisite_system.html.md.erb
@@ -167,7 +167,7 @@ See [WAN Configuration](../../reference/topics/elements_ref.html#topic_7B1CABCAD
          dispatcher-threads="2" order-policy="partition" manual-start="true" />
         ```
 
-        By default, this is set to false on gateway senders and the senders are started automatically.
+        By default, `manual-start` is set to false on gateway senders and the senders are started automatically.
 
 4.  If you have configured the gateway sender with `manual-start` equal to true, then start the gateway sender when appropriate. For persistent gateway senders, the appropriate time to start them is when all other members hosting persistent regions are started. In gfsh:
 
@@ -238,7 +238,8 @@ A gateway receiver configuration specifies a range of possible port numbers on w
 
 You can optionally configure gateway receivers to provide a specific IP address or host name for gateway sender connections. If you configure hostname-for-senders, locators will use the provided host name or IP address when instructing gateway senders on how to connect to gateway receivers. If you provide "" or null as the value, by default the gateway receiver's bind-address will be sent to clients.
 
-In addition, you can configure gateway receivers to start automatically or to require a manual start. By default, gateway receivers must be started manually.
+In addition, you can configure gateway receivers to start automatically or, by setting `manual-start` to true, to require a manual start. 
+By default, gateway receivers start automatically.
 
 **Note:**
 To configure a gateway receiver, you can use gfsh, cache.xml or Java API configurations as described below. For more information on configuring gateway receivers in gfsh, see [create gateway-receiver](../../tools_modules/gfsh/command-pages/create.html#topic_a4x_pb1_dk).
@@ -255,7 +256,7 @@ To configure a gateway receiver, you can use gfsh, cache.xml or Java API configu
 
     ``` pre
     <cache>
-      <gateway-receiver start-port="1530" end-port="1551" hostname-for-senders="gateway1.mycompany.com" manual-start="false" /> 
+      <gateway-receiver start-port="1530" end-port="1551" hostname-for-senders="gateway1.mycompany.com" /> 
        ... 
     </cache>
     ```
@@ -272,33 +273,20 @@ To configure a gateway receiver, you can use gfsh, cache.xml or Java API configu
     gateway.setEndPort(1551);
     gateway.setHostnameForSenders("gateway1.mycompany.com");
     GatewayReceiver receiver = gateway.create();
-    receiver.start();
     ```
 
     **Note:**
-    When using the Java API, you must create any region that might receive events from a remote site before you start the gateway receiver. Otherwise, batches of events could arrive from remote sites before the regions for those events have been created. If this occurs, the local site will throw exceptions because the receiving region does not exist yet. If you define regions in `cache.xml`, the correct startup order is handled automatically.
+    When using the Java API, you must create any region that might receive events from a remote site before you create the gateway receiver. Otherwise, batches of events could arrive from remote sites before the regions for those events have been created. If this occurs, the local site will throw exceptions because the receiving region does not yet exist. If you define regions in `cache.xml`, the correct startup order is handled automatically.
 
--   By default, `manual-start` is configured to **true** on gateway receivers. If you have not changed this configuration (either in gfsh or cache.xml), you must start your gateway receiver manually. For example, in gfsh:
+After starting new gateway receivers, you can execute the [load-balance gateway-sender](../../tools_modules/gfsh/command-pages/load-balance.html) command in `gfsh` so that a specific gateway sender will be able to rebalance its connections and connect new remote gateway receivers. Invoking this command redistributes gateway sender connections more evenly among all the gateway receivers.
 
-    ``` pre
-    gfsh>create gateway-receiver --manual-start=false
-    ```
-
--   In gfsh, if you have not disabled manual-start, execute the following command to start the gateway receiver:
-
-    ``` pre
-    gfsh>start gateway-receiver
-    ```
-
--   After starting new gateway receivers, you can execute the [load-balance gateway-sender](../../tools_modules/gfsh/command-pages/load-balance.html) command in `gfsh` so that a specific gateway sender will be able to rebalance its connections and connect new remote gateway receivers. Invoking this command redistributes gateway sender connections more evenly among all the gateway receivers.
-
-    Another option is to use the `GatewaySender.rebalance` Java API.
+Another option is to use the `GatewaySender.rebalance` Java API.
 
 As an example, assume the following scenario:
 
-1.  start 1 receiver in site ny
-2.  start 4 senders in site ln
-3.  start 3 additional receiver in NY
+1.  Create 1 receiver in site NY.
+2.  Create 4 senders in site LN.
+3.  Create 3 additional receivers in NY.
 
 You can then execute the following in gfsh to see the effects of rebalancing:
 

http://git-wip-us.apache.org/repos/asf/geode/blob/08154dd7/geode-docs/topologies_and_comm/topology_concepts/multisite_overview.html.md.erb
----------------------------------------------------------------------
diff --git a/geode-docs/topologies_and_comm/topology_concepts/multisite_overview.html.md.erb b/geode-docs/topologies_and_comm/topology_concepts/multisite_overview.html.md.erb
index f250f80..e7bb61d 100644
--- a/geode-docs/topologies_and_comm/topology_concepts/multisite_overview.html.md.erb
+++ b/geode-docs/topologies_and_comm/topology_concepts/multisite_overview.html.md.erb
@@ -108,7 +108,8 @@ A gateway receiver applies each region event to the same region or partition tha
 
 Gateway senders use any available gateway receiver in the target cluster to send region events. You can deploy gateway receiver configurations to multiple Geode members as needed for high availability and load balancing, however you can only host one gateway receiver per member.
 
-After you create a gateway receiver, you can configure the gateway receiver to start automatically or to require a manual start. The current default is to require a manual start for the gateway receiver (`manual-start` is set to true).
+After you create a gateway receiver, you can configure the gateway receiver to start automatically or to require a manual start. 
+By default, the gateway receiver starts automatically (`manual-start` is set to false).
 
 After you create and start a new gateway receiver at one WAN site, you can execute the [load-balance gateway-sender](../../tools_modules/gfsh/command-pages/load-balance.html#concept_fn2_qls_5q) command in `gfsh` for existing remote gateway senders so that the new receiver can pick up connections to gateway senders at different sites. You invoke this command on the gateway senders to redistribute connections more evenly among all the gateway receivers. Another option is to use the `GatewaySender.rebalance` Java API.
 


[19/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessStreamReader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessStreamReader.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessStreamReader.java
index b514c6a..39b900a 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessStreamReader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessStreamReader.java
@@ -14,15 +14,12 @@
  */
 package org.apache.geode.internal.process;
 
-import java.io.BufferedReader;
-import java.io.IOException;
+import static org.apache.commons.lang.Validate.isTrue;
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.InputStream;
-import java.io.InputStreamReader;
 
 import org.apache.commons.lang.SystemUtils;
-import org.apache.logging.log4j.Logger;
-
-import org.apache.geode.internal.logging.LogService;
 
 /**
  * Reads the output stream of a Process.
@@ -30,8 +27,8 @@ import org.apache.geode.internal.logging.LogService;
  * @since GemFire 7.0
  */
 public abstract class ProcessStreamReader implements Runnable {
-  private static final int DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLISECONDS = 5000;
-  private static final Logger logger = LogService.getLogger();
+
+  private static final int DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLIS = 5000;
 
   protected final Process process;
   protected final InputStream inputStream;
@@ -40,8 +37,11 @@ public abstract class ProcessStreamReader implements Runnable {
   private Thread thread;
 
   protected ProcessStreamReader(final Builder builder) {
+    notNull(builder, "Invalid builder '" + builder + "' specified");
+
     this.process = builder.process;
     this.inputStream = builder.inputStream;
+
     if (builder.inputListener == null) {
       this.inputListener = new InputListener() {
         @Override
@@ -59,44 +59,13 @@ public abstract class ProcessStreamReader implements Runnable {
     }
   }
 
-  @Override
-  public void run() {
-    final boolean isDebugEnabled = logger.isDebugEnabled();
-    if (isDebugEnabled) {
-      logger.debug("Running {}", this);
-    }
-    BufferedReader reader = null;
-    try {
-      reader = new BufferedReader(new InputStreamReader(inputStream));
-      String line;
-      while ((line = reader.readLine()) != null) {
-        this.inputListener.notifyInputLine(line);
-      }
-    } catch (IOException e) {
-      if (isDebugEnabled) {
-        logger.debug("Failure reading from buffered input stream: {}", e.getMessage(), e);
-      }
-    } finally {
-      try {
-        reader.close();
-      } catch (IOException e) {
-        if (isDebugEnabled) {
-          logger.debug("Failure closing buffered input stream reader: {}", e.getMessage(), e);
-        }
-      }
-      if (isDebugEnabled) {
-        logger.debug("Terminating {}", this);
-      }
-    }
-  }
-
   public ProcessStreamReader start() {
     synchronized (this) {
-      if (this.thread == null) {
-        this.thread = new Thread(this, createThreadName());
-        this.thread.setDaemon(true);
-        this.thread.start();
-      } else if (this.thread.isAlive()) {
+      if (thread == null) {
+        thread = new Thread(this, createThreadName());
+        thread.setDaemon(true);
+        thread.start();
+      } else if (thread.isAlive()) {
         throw new IllegalStateException(this + " has already started");
       } else {
         throw new IllegalStateException(this + " was stopped and cannot be restarted");
@@ -107,33 +76,23 @@ public abstract class ProcessStreamReader implements Runnable {
 
   public ProcessStreamReader stop() {
     synchronized (this) {
-      if (this.thread != null && this.thread.isAlive()) {
-        this.thread.interrupt();
-      } else if (this.thread != null) {
-        if (logger.isDebugEnabled()) {
-          logger.debug("{} has already been stopped", this);
-        }
-      } else {
-        if (logger.isDebugEnabled()) {
-          logger.debug("{} has not been started", this);
-        }
+      if (thread != null && thread.isAlive()) {
+        thread.interrupt();
       }
     }
     return this;
   }
 
   public ProcessStreamReader stopAsync(final long delayMillis) {
-    Runnable delayedStop = new Runnable() {
-      @Override
-      public void run() {
-        try {
-          Thread.sleep(delayMillis);
-        } catch (InterruptedException e) {
-        } finally {
-          stop();
-        }
+    Runnable delayedStop = () -> {
+      try {
+        Thread.sleep(delayMillis);
+      } catch (InterruptedException ignored) {
+      } finally {
+        stop();
       }
     };
+
     String threadName =
         getClass().getSimpleName() + " stopAfterDelay Thread @" + Integer.toHexString(hashCode());
     Thread thread = new Thread(delayedStop, threadName);
@@ -144,14 +103,14 @@ public abstract class ProcessStreamReader implements Runnable {
 
   public boolean isRunning() {
     synchronized (this) {
-      if (this.thread != null) {
-        return this.thread.isAlive();
+      if (thread != null) {
+        return thread.isAlive();
       }
     }
     return false;
   }
 
-  public void join() throws InterruptedException {
+  public ProcessStreamReader join() throws InterruptedException {
     Thread thread;
     synchronized (this) {
       thread = this.thread;
@@ -159,9 +118,10 @@ public abstract class ProcessStreamReader implements Runnable {
     if (thread != null) {
       thread.join();
     }
+    return this;
   }
 
-  public void join(final long millis) throws InterruptedException {
+  public ProcessStreamReader join(final long millis) throws InterruptedException {
     Thread thread;
     synchronized (this) {
       thread = this.thread;
@@ -169,9 +129,10 @@ public abstract class ProcessStreamReader implements Runnable {
     if (thread != null) {
       thread.join(millis);
     }
+    return this;
   }
 
-  public void join(final long millis, final int nanos) throws InterruptedException {
+  public ProcessStreamReader join(final long millis, final int nanos) throws InterruptedException {
     Thread thread;
     synchronized (this) {
       thread = this.thread;
@@ -179,47 +140,44 @@ public abstract class ProcessStreamReader implements Runnable {
     if (thread != null) {
       thread.join(millis, nanos);
     }
+    return this;
   }
 
   @Override
   public String toString() {
-    final StringBuilder sb = new StringBuilder(getClass().getSimpleName());
+    StringBuilder sb = new StringBuilder(getClass().getSimpleName());
     sb.append(" Thread").append(" #").append(System.identityHashCode(this));
-    sb.append(" alive=").append(isRunning()); // this.thread == null ? false :
-                                              // this.thread.isAlive());
-    sb.append(" listener=").append(this.inputListener);
+    sb.append(" alive=").append(isRunning());
+    sb.append(" listener=").append(inputListener);
     return sb.toString();
   }
 
   private String createThreadName() {
-    return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
+    return getClass().getSimpleName() + '@' + Integer.toHexString(hashCode());
   }
 
   /**
    * Defines the callback for lines of output found in the stream.
    */
-  public static interface InputListener {
-    public void notifyInputLine(String line);
+  public interface InputListener {
+    void notifyInputLine(final String line);
   }
 
   /** Default ReadingMode is BLOCKING */
-  public static enum ReadingMode {
-    BLOCKING, NON_BLOCKING;
-  }
-
-  public static String waitAndCaptureProcessStandardOutputStream(final Process process) {
-    return waitAndCaptureProcessStandardOutputStream(process,
-        DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLISECONDS);
+  public enum ReadingMode {
+    BLOCKING, NON_BLOCKING
   }
 
-  public static String waitAndCaptureProcessStandardOutputStream(final Process process,
+  private static String waitAndCaptureProcessStandardOutputStream(final Process process,
       final long waitTimeMilliseconds) {
+    notNull(process, "Invalid process '" + process + "' specified");
+
     return waitAndCaptureProcessStream(process, process.getInputStream(), waitTimeMilliseconds);
   }
 
   public static String waitAndCaptureProcessStandardErrorStream(final Process process) {
     return waitAndCaptureProcessStandardErrorStream(process,
-        DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLISECONDS);
+        DEFAULT_PROCESS_OUTPUT_WAIT_TIME_MILLIS);
   }
 
   public static String waitAndCaptureProcessStandardErrorStream(final Process process,
@@ -228,8 +186,8 @@ public abstract class ProcessStreamReader implements Runnable {
   }
 
   private static String waitAndCaptureProcessStream(final Process process,
-      final InputStream processInputStream, long waitTimeMilliseconds) {
-    final StringBuffer buffer = new StringBuffer();
+      final InputStream processInputStream, final long waitTimeMilliseconds) {
+    StringBuffer buffer = new StringBuffer();
 
     InputListener inputListener = line -> {
       buffer.append(line);
@@ -242,7 +200,7 @@ public abstract class ProcessStreamReader implements Runnable {
     try {
       reader.start();
 
-      final long endTime = (System.currentTimeMillis() + waitTimeMilliseconds);
+      long endTime = System.currentTimeMillis() + waitTimeMilliseconds;
 
       while (System.currentTimeMillis() < endTime) {
         try {
@@ -259,15 +217,16 @@ public abstract class ProcessStreamReader implements Runnable {
 
   /**
    * Builds a ProcessStreamReader.
-   * 
+   *
    * @since GemFire 8.2
    */
   public static class Builder {
-    protected Process process;
-    protected InputStream inputStream;
-    protected InputListener inputListener;
-    protected long continueReadingMillis = 0;
-    protected ReadingMode readingMode = ReadingMode.BLOCKING;
+
+    final Process process;
+    InputStream inputStream;
+    InputListener inputListener;
+    long continueReadingMillis = 0;
+    ReadingMode readingMode = ReadingMode.BLOCKING;
 
     public Builder(final Process process) {
       this.process = process;
@@ -297,16 +256,12 @@ public abstract class ProcessStreamReader implements Runnable {
     }
 
     public ProcessStreamReader build() {
-      if (process == null) {
-        throw new NullPointerException("process may not be null");
-      }
-      if (inputStream == null) {
-        throw new NullPointerException("inputStream may not be null");
-      }
-      if (continueReadingMillis < 0) {
-        throw new IllegalArgumentException("continueReadingMillis must zero or positive");
-      }
-      switch (this.readingMode) {
+      notNull(process, "Invalid process '" + process + "' specified");
+      notNull(inputStream, "Invalid inputStream '" + inputStream + "' specified");
+      isTrue(continueReadingMillis >= 0,
+          "Invalid continueReadingMillis '" + continueReadingMillis + "' specified");
+
+      switch (readingMode) {
         case NON_BLOCKING:
           return new NonBlockingProcessStreamReader(this);
         default:

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessTerminatedAbnormallyException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessTerminatedAbnormallyException.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessTerminatedAbnormallyException.java
deleted file mode 100644
index 510353c..0000000
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessTerminatedAbnormallyException.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package org.apache.geode.internal.process;
-
-import org.apache.geode.GemFireException;
-
-/**
- * The ProcessTerminatedAbnormallyException class is a GemFireException (or RuntimeException)
- * indicating that a process terminated abnormally, and it's exit code is captured along with this
- * RuntimeException.
- * </p>
- * 
- * @see org.apache.geode.GemFireException
- * @since GemFire 7.0
- */
-public class ProcessTerminatedAbnormallyException extends GemFireException {
-  private static final long serialVersionUID = -1181367425266595492L;
-  private final int exitValue;
-
-  /**
-   * Constructs an instance of the ProcessTerminatedAbnormallyException class with the given exit
-   * value of the process.
-   * </p>
-   * 
-   * @param exitValue an integer value indicating the exit value of the terminated process.
-   */
-  public ProcessTerminatedAbnormallyException(final int exitValue) {
-    this.exitValue = exitValue;
-  }
-
-  /**
-   * Constructs an instance of the ProcessTerminatedAbnormallyException class with the given exit
-   * value of the process and a message indicating the reason of the abnormal termination.
-   * </p>
-   * 
-   * @param exitValue an integer value indicating the exit value of the terminated process.
-   * @param message a String indicating the reason the process terminated abnormally.
-   */
-  public ProcessTerminatedAbnormallyException(final int exitValue, final String message) {
-    super(message);
-    this.exitValue = exitValue;
-  }
-
-  /**
-   * Constructs an instance of the ProcessTerminatedAbnormallyException class with the given exit
-   * value of the process and a Throwable representing the underlying cause of the process
-   * termination.
-   * </p>
-   * 
-   * @param exitValue an integer value indicating the exit value of the terminated process.
-   * @param cause a Throwable encapsulating the undelrying cause of the process termination.
-   */
-  public ProcessTerminatedAbnormallyException(final int exitValue, final Throwable cause) {
-    super(cause);
-    this.exitValue = exitValue;
-  }
-
-  /**
-   * Constructs an instance of the ProcessTerminatedAbnormallyException class with the given exit
-   * value of the process as well as a message indicating the reason of the abnormal termination
-   * along with a Throwable representing the underlying cause of the process termination.
-   * </p>
-   * 
-   * @param exitValue an integer value indicating the exit value of the terminated process.
-   * @param message a String indicating the reason the process terminated abnormally.
-   * @param cause a Throwable encapsulating the undelrying cause of the process termination.
-   */
-  public ProcessTerminatedAbnormallyException(final int exitValue, final String message,
-      final Throwable cause) {
-    super(message, cause);
-    this.exitValue = exitValue;
-  }
-
-  /**
-   * Gets the exit value returned by the process when it terminated.
-   * </p>
-   * 
-   * @return an integer value indicating the exit value of the terminated process.
-   */
-  public int getExitValue() {
-    return exitValue;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessType.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessType.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessType.java
index b15030d..86f9dc1 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessType.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessType.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.StringUtils.EMPTY;
+
 import org.apache.geode.distributed.internal.DistributionConfig;
 
 /**
@@ -25,7 +27,7 @@ import org.apache.geode.distributed.internal.DistributionConfig;
 public enum ProcessType {
   LOCATOR("LOCATOR", "vf.gf.locator"), SERVER("SERVER", "vf.gf.server");
 
-  public static final String TEST_PREFIX_PROPERTY =
+  public static final String PROPERTY_TEST_PREFIX =
       DistributionConfig.GEMFIRE_PREFIX + "test.ProcessType.TEST_PREFIX";
 
   private static final String SUFFIX_PID = "pid";
@@ -36,33 +38,33 @@ public enum ProcessType {
   private final String name;
   private final String fileName;
 
-  private ProcessType(final String name, final String fileName) {
+  ProcessType(final String name, final String fileName) {
     this.name = name;
     this.fileName = fileName;
   }
 
   public String getPidFileName() {
-    return new StringBuilder(System.getProperty(TEST_PREFIX_PROPERTY, "")).append(this.fileName)
-        .append(".").append(SUFFIX_PID).toString();
+    return new StringBuilder(System.getProperty(PROPERTY_TEST_PREFIX, EMPTY)).append(fileName)
+        .append('.').append(SUFFIX_PID).toString();
   }
 
   public String getStopRequestFileName() {
-    return new StringBuilder(System.getProperty(TEST_PREFIX_PROPERTY, "")).append(this.fileName)
-        .append(".").append(SUFFIX_STOP_REQUEST).toString();
+    return new StringBuilder(System.getProperty(PROPERTY_TEST_PREFIX, EMPTY)).append(fileName)
+        .append('.').append(SUFFIX_STOP_REQUEST).toString();
   }
 
   public String getStatusRequestFileName() {
-    return new StringBuilder(System.getProperty(TEST_PREFIX_PROPERTY, "")).append(this.fileName)
-        .append(".").append(SUFFIX_STATUS_REQUEST).toString();
+    return new StringBuilder(System.getProperty(PROPERTY_TEST_PREFIX, EMPTY)).append(fileName)
+        .append('.').append(SUFFIX_STATUS_REQUEST).toString();
   }
 
   public String getStatusFileName() {
-    return new StringBuilder(System.getProperty(TEST_PREFIX_PROPERTY, "")).append(this.fileName)
-        .append(".").append(SUFFIX_STATUS).toString();
+    return new StringBuilder(System.getProperty(PROPERTY_TEST_PREFIX, EMPTY)).append(fileName)
+        .append('.').append(SUFFIX_STATUS).toString();
   }
 
   @Override
   public String toString() {
-    return this.name;
+    return name;
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessUtils.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessUtils.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessUtils.java
index 3ff74d8..3cf850f 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessUtils.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessUtils.java
@@ -14,14 +14,16 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.isTrue;
+import static org.apache.commons.lang.Validate.notEmpty;
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
 import java.lang.management.ManagementFactory;
 
-import org.apache.geode.internal.util.IOUtils;
-
 /**
  * Utility operations for processes such as identifying the process id (pid).
  * 
@@ -31,7 +33,9 @@ public class ProcessUtils {
 
   private static InternalProcessUtils internal = initializeInternalProcessUtils();
 
-  private ProcessUtils() {}
+  private ProcessUtils() {
+    // nothing
+  }
 
   /**
    * Returns the pid for this process.
@@ -50,8 +54,11 @@ public class ProcessUtils {
    * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails
    */
   public static int identifyPid(final String name) throws PidUnavailableException {
+    notEmpty(name, "Invalid name '" + name + "' specified");
+
+
     try {
-      final int index = name.indexOf("@");
+      final int index = name.indexOf('@');
       if (index < 0) {
         throw new PidUnavailableException("Unable to parse pid from " + name);
       }
@@ -69,6 +76,8 @@ public class ProcessUtils {
    * @return true if the pid matches a currently running process
    */
   public static boolean isProcessAlive(final int pid) {
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
     return internal.isProcessAlive(pid);
   }
 
@@ -80,6 +89,8 @@ public class ProcessUtils {
    * @return true if the Process is a currently running process
    */
   public static boolean isProcessAlive(final Process process) {
+    notNull(process, "Invalid process '" + process + "' specified");
+
     return process.isAlive();
   }
 
@@ -91,16 +102,17 @@ public class ProcessUtils {
    * @return true if the process was terminated by this operation
    */
   public static boolean killProcess(final int pid) {
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
     return internal.killProcess(pid);
   }
 
   public static int readPid(final File pidFile) throws IOException {
-    BufferedReader reader = null;
-    try {
-      reader = new BufferedReader(new FileReader(pidFile));
+    notNull(pidFile, "Invalid pidFile '" + pidFile + "' specified");
+    isTrue(pidFile.exists(), "Nonexistent pidFile '" + pidFile + "' specified");
+
+    try (BufferedReader reader = new BufferedReader(new FileReader(pidFile))) {
       return Integer.parseInt(reader.readLine());
-    } finally {
-      IOUtils.close(reader);
     }
   }
 
@@ -125,40 +137,33 @@ public class ProcessUtils {
       Class.forName("com.sun.tools.attach.VirtualMachine");
       Class.forName("com.sun.tools.attach.VirtualMachineDescriptor");
       return new AttachProcessUtils();
-    } catch (ClassNotFoundException e) {
-      // fall through
-    } catch (LinkageError e) {
+    } catch (ClassNotFoundException | LinkageError ignored) {
       // fall through
     }
 
     // 2) try NativeCalls but make sure it doesn't throw UnsupportedOperationException
     try {
-      // TODO: get rid of Class.forName usage if NativeCalls always safely loads
+      // consider getting rid of Class.forName usage if NativeCalls always safely loads
       Class.forName("org.apache.geode.internal.shared.NativeCalls");
-      NativeProcessUtils inst = new NativeProcessUtils();
-      boolean result = inst.isProcessAlive(identifyPid());
+      NativeProcessUtils nativeProcessUtils = new NativeProcessUtils();
+      boolean result = nativeProcessUtils.isProcessAlive(identifyPid());
       if (result) {
-        return inst;
+        return nativeProcessUtils;
       }
-    } catch (ClassNotFoundException e) {
-      // fall through
-    } catch (LinkageError e) {
-      // fall through
-    } catch (PidUnavailableException e) {
-      // fall through (log warning??)
-    } catch (UnsupportedOperationException e) {
+    } catch (ClassNotFoundException | LinkageError | PidUnavailableException
+        | UnsupportedOperationException ignored) {
       // fall through
     }
 
-    // 3) TODO: log warning and then proceed with no-op
+    // 3) consider logging warning and then proceed with no-op
     return new InternalProcessUtils() {
       @Override
-      public boolean isProcessAlive(int pid) {
+      public boolean isProcessAlive(final int pid) {
         return false;
       }
 
       @Override
-      public boolean killProcess(int pid) {
+      public boolean killProcess(final int pid) {
         return false;
       }
 
@@ -178,12 +183,13 @@ public class ProcessUtils {
    * Defines the SPI for ProcessUtils
    */
   interface InternalProcessUtils {
-    public boolean isProcessAlive(int pid);
 
-    public boolean killProcess(int pid);
+    boolean isProcessAlive(final int pid);
+
+    boolean killProcess(final int pid);
 
-    public boolean isAvailable();
+    boolean isAvailable();
 
-    public boolean isAttachApiAvailable();
+    boolean isAttachApiAvailable();
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatus.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatus.java b/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatus.java
index a207994..ede0bdc 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatus.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatus.java
@@ -14,14 +14,15 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.notNull;
+
 import org.apache.logging.log4j.Logger;
 
-import org.apache.geode.internal.logging.LogService;
 import org.apache.geode.i18n.StringId;
+import org.apache.geode.internal.logging.LogService;
 
 /**
  * Extracted from LogWriterImpl and changed to static.
- * 
  */
 public class StartupStatus {
   private static final Logger logger = LogService.getLogger();
@@ -29,14 +30,21 @@ public class StartupStatus {
   /** protected by static synchronized */
   private static StartupStatusListener listener;
 
+  private StartupStatus() {
+    // do nothing
+  }
+
   /**
    * Writes both a message and exception to this writer. If a startup listener is registered, the
    * message will be written to the listener as well to be reported to a user.
-   * 
+   *
    * @since GemFire 7.0
    */
-  public static synchronized void startup(StringId msgID, Object[] params) {
-    String message = msgID.toLocalizedString(params);
+  public static synchronized void startup(final StringId msgId, final Object... params) {
+    notNull(msgId, "Invalid msgId '" + msgId + "' specified");
+    notNull(params, "Invalid params '" + params + "' specified");
+
+    String message = msgId.toLocalizedString(params);
 
     if (listener != null) {
       listener.setStatus(message);
@@ -45,7 +53,7 @@ public class StartupStatus {
     logger.info(message);
   }
 
-  public static synchronized void setListener(StartupStatusListener listener) {
+  public static synchronized void setListener(final StartupStatusListener listener) {
     StartupStatus.listener = listener;
   }
 

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatusListener.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatusListener.java b/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatusListener.java
index 0e3abb7..07a20fc 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatusListener.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/StartupStatusListener.java
@@ -24,5 +24,5 @@ public interface StartupStatusListener {
    * Report the current status of system startup. The status message reported to this method should
    * already be internationalized.
    */
-  public void setStatus(String status);
+  void setStatus(final String status);
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/UnableToControlProcessException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/UnableToControlProcessException.java b/geode-core/src/main/java/org/apache/geode/internal/process/UnableToControlProcessException.java
index ac4e4c8..3e8daec 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/UnableToControlProcessException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/UnableToControlProcessException.java
@@ -24,23 +24,23 @@ public class UnableToControlProcessException extends Exception {
   private static final long serialVersionUID = 7579463534993125290L;
 
   /**
-   * Creates a new <code>UnableToControlProcessException</code>.
+   * Creates a new {@code UnableToControlProcessException}.
    */
   public UnableToControlProcessException(final String message) {
     super(message);
   }
 
   /**
-   * Creates a new <code>UnableToControlProcessException</code> that was caused by a given exception
+   * Creates a new {@code UnableToControlProcessException} that was caused by a given exception
    */
-  public UnableToControlProcessException(final String message, final Throwable thr) {
-    super(message, thr);
+  public UnableToControlProcessException(final String message, final Throwable cause) {
+    super(message, cause);
   }
 
   /**
-   * Creates a new <code>UnableToControlProcessException</code> that was caused by a given exception
+   * Creates a new {@code UnableToControlProcessException} that was caused by a given exception
    */
-  public UnableToControlProcessException(final Throwable thr) {
-    super(thr.getMessage(), thr);
+  public UnableToControlProcessException(final Throwable cause) {
+    super(cause.getMessage(), cause);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandler.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandler.java b/geode-core/src/main/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandler.java
index 6a44558..2658d5f 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandler.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/signal/AbstractSignalNotificationHandler.java
@@ -12,9 +12,10 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.internal.process.signal;
 
+import static org.apache.commons.lang.StringUtils.EMPTY;
+
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -25,44 +26,34 @@ import java.util.Set;
 
 /**
  * The AbstractSignalNotificationHandler class...
- * </p>
- * 
- * @see org.apache.geode.internal.process.signal.Signal
- * @see org.apache.geode.internal.process.signal.SignalEvent
- * @see org.apache.geode.internal.process.signal.SignalListener
+ *
  * @since GemFire 7.0
  */
-@SuppressWarnings("unused")
 public abstract class AbstractSignalNotificationHandler {
 
-  // NOTE use the enumerated type instead...
+  /**
+   * @deprecated use the enumerated type instead...
+   */
   @Deprecated
   protected static final List<String> SIGNAL_NAMES;
 
   // Based on Open BSD OS Signals...
   static {
-    final String[] SIGNAL_NAMES_ARRAY =
-        new String[] {"", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "EMT", "FPE", "KILL", "BUS",
-            "SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", "CONT", "CHLD", "TTIN",
-            "TTOU", "IO", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO", "USR1", "USR2"};
+    String[] SIGNAL_NAMES_ARRAY = new String[] {EMPTY, "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT",
+        "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP",
+        "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO",
+        "USR1", "USR2"};
 
     SIGNAL_NAMES = Collections.unmodifiableList(Arrays.asList(SIGNAL_NAMES_ARRAY));
   }
 
-  protected static final SignalListener LOGGING_SIGNAL_LISTENER = new SignalListener() {
-    public void handle(final SignalEvent event) {
-      System.out.printf("Logging SignalListener Received Signal '%1$s' (%2$d)%n",
+  private static final SignalListener LOGGING_SIGNAL_LISTENER =
+      event -> System.out.printf("Logging SignalListener Received Signal '%1$s' (%2$d)%n",
           event.getSignal().getName(), event.getSignal().getNumber());
-    }
-  };
 
-  protected static final SignalListener NO_OP_SIGNAL_LISTENER = new SignalListener() {
-    public void handle(final SignalEvent event) {
-      // no op
-    }
-  };
-
-  // Map used to register SignalListeners with SignalHandlers...
+  /**
+   * Map used to register SignalListeners with SignalHandlers...
+   */
   private final Map<Signal, Set<SignalListener>> signalListeners =
       Collections.synchronizedMap(new HashMap<Signal, Set<SignalListener>>(Signal.values().length));
 
@@ -80,52 +71,52 @@ public abstract class AbstractSignalNotificationHandler {
     }
   }
 
-  protected static void assertValidArgument(final boolean valid, final String message,
+  static void assertValidArgument(final boolean valid, final String message,
       final Object... arguments) {
     if (!valid) {
       throw new IllegalArgumentException(String.format(message, arguments));
     }
   }
 
-  public AbstractSignalNotificationHandler() {
-    for (final Signal signal : Signal.values()) {
-      signalListeners.put(signal, Collections.synchronizedSet(new HashSet<SignalListener>()));
+  protected AbstractSignalNotificationHandler() {
+    for (Signal signal : Signal.values()) {
+      signalListeners.put(signal, Collections.synchronizedSet(new HashSet<>()));
     }
     // NOTE uncomment for debugging purposes...
-    // registerListener(LOGGING_SIGNAL_LISTENER);
+    // debug();
   }
 
-  public boolean hasListeners(final Signal signal) {
+  boolean hasListeners(final Signal signal) {
     return !signalListeners.get(signal).isEmpty();
   }
 
-  public boolean isListening(final SignalListener listener) {
+  boolean isListening(final SignalListener listener) {
     boolean registered = false;
 
-    for (final Signal signal : Signal.values()) {
+    for (Signal signal : Signal.values()) {
       registered |= isListening(listener, signal);
     }
 
     return registered;
   }
 
-  public boolean isListening(final SignalListener listener, final Signal signal) {
+  boolean isListening(final SignalListener listener, final Signal signal) {
     assertNotNull(signal,
         "The signal to determine whether the listener is registered listening for cannot be null!");
     return signalListeners.get(signal).contains(listener);
   }
 
   protected void notifyListeners(final SignalEvent event) {
-    final Set<SignalListener> listeners = signalListeners.get(event.getSignal());
+    Set<SignalListener> listeners = signalListeners.get(event.getSignal());
     Set<SignalListener> localListeners = Collections.emptySet();
 
     if (listeners != null) {
       synchronized (listeners) {
-        localListeners = new HashSet<SignalListener>(listeners);
+        localListeners = new HashSet<>(listeners);
       }
     }
 
-    for (final SignalListener listener : localListeners) {
+    for (SignalListener listener : localListeners) {
       listener.handle(event);
     }
   }
@@ -136,14 +127,14 @@ public abstract class AbstractSignalNotificationHandler {
 
     boolean registered = false;
 
-    for (final Signal signal : Signal.values()) {
+    for (Signal signal : Signal.values()) {
       registered |= registerListener(listener, signal);
     }
 
     return registered;
   }
 
-  public boolean registerListener(final SignalListener listener, final Signal signal) {
+  boolean registerListener(final SignalListener listener, final Signal signal) {
     assertNotNull(signal, "The signal to register the listener for cannot be null!");
     assertNotNull(listener,
         "The SignalListener being registered to listen for '%1$s' signals cannot be null!",
@@ -155,23 +146,23 @@ public abstract class AbstractSignalNotificationHandler {
   public boolean unregisterListener(final SignalListener listener) {
     boolean unregistered = false;
 
-    for (final Signal signal : Signal.values()) {
+    for (Signal signal : Signal.values()) {
       unregistered |= unregisterListener(listener, signal);
     }
 
     return unregistered;
   }
 
-  public boolean unregisterListener(final SignalListener listener, final Signal signal) {
+  boolean unregisterListener(final SignalListener listener, final Signal signal) {
     assertNotNull(signal, "The signal from which to unregister the listener cannot be null!");
 
     return signalListeners.get(signal).remove(listener);
   }
 
-  public boolean unregisterListeners(final Signal signal) {
+  boolean unregisterListeners(final Signal signal) {
     assertNotNull(signal, "The signal from which to unregister all listeners cannot be null!");
 
-    final Set<SignalListener> listeners = signalListeners.get(signal);
+    Set<SignalListener> listeners = signalListeners.get(signal);
 
     synchronized (listeners) {
       listeners.clear();
@@ -179,4 +170,10 @@ public abstract class AbstractSignalNotificationHandler {
     }
   }
 
+  /**
+   * Do not delete.
+   */
+  private void debug() {
+    registerListener(LOGGING_SIGNAL_LISTENER);
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/signal/Signal.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/signal/Signal.java b/geode-core/src/main/java/org/apache/geode/internal/process/signal/Signal.java
index 78b19db..9dfdfef 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/signal/Signal.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/signal/Signal.java
@@ -12,17 +12,15 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.internal.process.signal;
 
 import org.apache.commons.lang.StringUtils;
 
 /**
  * Signals defined in the enumerated type were based on Open BSD and the IBM JVM...
- * </p>
- * 
- * @see org.apache.geode.internal.process.signal.SignalType
+ *
  * @since GemFire 7.0
+ *
  * @see <a href=
  *      "http://www.fromdual.com/operating-system-signals">http://www.fromdual.com/operating-system-signals</a>
  * @see <a href=
@@ -30,7 +28,6 @@ import org.apache.commons.lang.StringUtils;
  * @see <a href=
  *      "http://publib.boulder.ibm.com/infocenter/java7sdk/v7r0/index.jsp?topic=%2Fcom.ibm.java.aix.70.doc%2Fuser%2Fsighand.html">http://publib.boulder.ibm.com/infocenter/java7sdk/v7r0/index.jsp?topic=%2Fcom.ibm.java.aix.70.doc%2Fuser%2Fsighand.html</a>
  */
-@SuppressWarnings("unused")
 public enum Signal {
   SIGHUP(1, "HUP", SignalType.INTERRUPT, "Hang up. JVM exits normally."),
   SIGINT(2, "INT", SignalType.INTERRUPT, "Interactive attention (CTRL-C). JVM exits normally."),
@@ -93,7 +90,7 @@ public enum Signal {
   }
 
   public static Signal valueOfName(final String name) {
-    for (final Signal signal : values()) {
+    for (Signal signal : values()) {
       if (signal.getName().equalsIgnoreCase(name)) {
         return signal;
       }
@@ -102,16 +99,6 @@ public enum Signal {
     return null;
   }
 
-  public static Signal valueOfNumber(final int number) {
-    for (final Signal signal : values()) {
-      if (signal.getNumber() == number) {
-        return signal;
-      }
-    }
-
-    return null;
-  }
-
   public String getDescription() {
     return description;
   }
@@ -132,5 +119,4 @@ public enum Signal {
   public String toString() {
     return "SIG".concat(getName());
   }
-
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalEvent.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalEvent.java b/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalEvent.java
index 7038337..d012afa 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalEvent.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalEvent.java
@@ -12,19 +12,17 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.internal.process.signal;
 
 import java.util.EventObject;
 
 /**
  * The SignalEvent class...
- * </p>
- * 
+ *
  * @see java.util.EventObject
+ *
  * @since GemFire 7.0
  */
-@SuppressWarnings("unused")
 public class SignalEvent extends EventObject {
 
   private final Signal signal;
@@ -36,16 +34,15 @@ public class SignalEvent extends EventObject {
   }
 
   public Signal getSignal() {
-    return this.signal;
+    return signal;
   }
 
   @Override
   public String toString() {
-    final StringBuilder buffer = new StringBuilder(getClass().getSimpleName());
+    StringBuilder buffer = new StringBuilder(getClass().getSimpleName());
     buffer.append("{ signal = ").append(getSignal());
     buffer.append(", source = ").append(getSource());
     buffer.append("}");
     return buffer.toString();
   }
-
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalListener.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalListener.java b/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalListener.java
index 501b9db..e874480 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalListener.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalListener.java
@@ -12,20 +12,18 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.internal.process.signal;
 
 import java.util.EventListener;
 
 /**
- * <p>
  * The SignalListener class...
- * </p>
- * 
+ *
  * @see java.util.EventListener
+ *
  * @since GemFire 7.0
  */
-@SuppressWarnings("unused")
 public interface SignalListener extends EventListener {
+
   void handle(SignalEvent event);
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalType.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalType.java b/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalType.java
index 9545dab..f29dc35 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalType.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/signal/SignalType.java
@@ -12,13 +12,11 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.internal.process.signal;
 
 /**
  * The SignalType class...
- * </p>
- * 
+ *
  * @since GemFire 7.0
  */
 public enum SignalType {
@@ -38,7 +36,6 @@ public enum SignalType {
 
   @Override
   public String toString() {
-    return this.description;
+    return description;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
index 9b743c8..8080e3f 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartServerCommand.java
@@ -35,7 +35,6 @@ import org.apache.geode.internal.OSProcess;
 import org.apache.geode.internal.i18n.LocalizedStrings;
 import org.apache.geode.internal.lang.StringUtils;
 import org.apache.geode.internal.lang.SystemUtils;
-import org.apache.geode.internal.process.ClusterConfigurationNotAvailableException;
 import org.apache.geode.internal.process.ProcessStreamReader;
 import org.apache.geode.internal.process.ProcessType;
 import org.apache.geode.internal.util.IOUtils;
@@ -407,8 +406,6 @@ public class StartServerCommand implements GfshCommand {
       return ResultBuilder.createUserErrorResult(message);
     } catch (IllegalStateException e) {
       return ResultBuilder.createUserErrorResult(e.getMessage());
-    } catch (ClusterConfigurationNotAvailableException e) {
-      return ResultBuilder.createShellClientErrorResult(e.getMessage());
     } catch (VirtualMachineError e) {
       SystemFailure.initiateFailure(e);
       throw e;

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTest.java
index 4766653..9b0bedf 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTest.java
@@ -14,8 +14,16 @@
  */
 package org.apache.geode.distributed;
 
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.test.junit.categories.IntegrationTest;
+import static org.apache.geode.distributed.AbstractLauncher.loadGemFireProperties;
+import static org.apache.geode.distributed.ConfigurationProperties.GROUPS;
+import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.Properties;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -23,21 +31,16 @@ import org.junit.experimental.categories.Category;
 import org.junit.rules.TemporaryFolder;
 import org.junit.rules.TestName;
 
-import java.io.File;
-import java.io.FileWriter;
-import java.util.Properties;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.apache.geode.distributed.ConfigurationProperties.*;
+import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
- * Integration tests for AbstractLauncher class. These tests require file system I/O.
+ * Integration tests for {@link AbstractLauncher} that require file system I/O.
  */
 @Category(IntegrationTest.class)
 public class AbstractLauncherIntegrationTest {
 
-  private File gemfirePropertiesFile;
-  private Properties expectedGemfireProperties;
+  private File propertiesFile;
+  private Properties expectedProperties;
 
   @Rule
   public final TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -47,26 +50,20 @@ public class AbstractLauncherIntegrationTest {
 
   @Before
   public void setUp() throws Exception {
-    this.gemfirePropertiesFile =
-        this.temporaryFolder.newFile(DistributionConfig.GEMFIRE_PREFIX + "properties");
+    propertiesFile = temporaryFolder.newFile(GEMFIRE_PREFIX + "properties");
 
-    this.expectedGemfireProperties = new Properties();
-    this.expectedGemfireProperties.setProperty(NAME, "memberOne");
-    this.expectedGemfireProperties.setProperty(GROUPS, "groupOne, groupTwo");
-    this.expectedGemfireProperties.store(new FileWriter(this.gemfirePropertiesFile, false),
-        this.testName.getMethodName());
+    expectedProperties = new Properties();
+    expectedProperties.setProperty(NAME, "memberOne");
+    expectedProperties.setProperty(GROUPS, "groupOne, groupTwo");
+    expectedProperties.store(new FileWriter(propertiesFile, false), testName.getMethodName());
 
-    assertThat(this.gemfirePropertiesFile).isNotNull();
-    assertThat(this.gemfirePropertiesFile.exists()).isTrue();
-    assertThat(this.gemfirePropertiesFile.isFile()).isTrue();
+    assertThat(propertiesFile).exists().isFile();
   }
 
   @Test
-  public void testLoadGemFirePropertiesFromFile() throws Exception {
-    final Properties actualGemFireProperties =
-        AbstractLauncher.loadGemFireProperties(this.gemfirePropertiesFile.toURI().toURL());
+  public void loadGemFirePropertiesFromFile() throws Exception {
+    Properties loadedProperties = loadGemFireProperties(propertiesFile.toURI().toURL());
 
-    assertThat(actualGemFireProperties).isNotNull();
-    assertThat(actualGemFireProperties).isEqualTo(this.expectedGemfireProperties);
+    assertThat(loadedProperties).isEqualTo(expectedProperties);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTestCase.java
deleted file mode 100755
index bf6a854..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherIntegrationTestCase.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.internal.process.PidUnavailableException;
-import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.internal.util.IOUtils;
-import org.apache.geode.internal.util.StopWatch;
-import org.apache.logging.log4j.Logger;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.contrib.java.lang.system.RestoreSystemProperties;
-import org.junit.rules.TestName;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.nio.file.Files;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * @since GemFire 8.0
- */
-public abstract class AbstractLauncherIntegrationTestCase {
-  protected static final Logger logger = LogService.getLogger();
-
-  protected static final int WAIT_FOR_PROCESS_TO_DIE_TIMEOUT = 5 * 60 * 1000; // 5 minutes
-  protected static final int TIMEOUT_MILLISECONDS = WAIT_FOR_PROCESS_TO_DIE_TIMEOUT;
-  protected static final int WAIT_FOR_FILE_CREATION_TIMEOUT = 10 * 1000; // 10s
-  protected static final int WAIT_FOR_FILE_DELETION_TIMEOUT = 10 * 1000; // 10s
-  protected static final int WAIT_FOR_MBEAN_TIMEOUT = 10 * 1000; // 10s
-  protected static final int INTERVAL_MILLISECONDS = 100;
-
-  private static final String EXPECTED_EXCEPTION_ADD =
-      "<ExpectedException action=add>{}</ExpectedException>";
-  private static final String EXPECTED_EXCEPTION_REMOVE =
-      "<ExpectedException action=remove>{}</ExpectedException>";
-  private static final String EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED =
-      "MBean Not Registered In GemFire Domain";
-
-  protected volatile ServerSocket socket;
-
-  protected volatile File pidFile;
-  protected volatile File stopRequestFile;
-  protected volatile File statusRequestFile;
-  protected volatile File statusFile;
-
-  @Rule
-  public TestName testName = new TestName();
-
-  @Rule
-  public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
-
-  @Before
-  public final void setUpAbstractLauncherIntegrationTestCase() throws Exception {
-    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + MCAST_PORT, Integer.toString(0));
-    logger.info(EXPECTED_EXCEPTION_ADD, EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED);
-  }
-
-  @After
-  public final void tearDownAbstractLauncherIntegrationTestCase() throws Exception {
-    logger.info(EXPECTED_EXCEPTION_REMOVE, EXPECTED_EXCEPTION_MBEAN_NOT_REGISTERED);
-    if (this.socket != null) {
-      this.socket.close();
-      this.socket = null;
-    }
-    delete(this.pidFile);
-    this.pidFile = null;
-    delete(this.stopRequestFile);
-    this.stopRequestFile = null;
-    delete(this.statusRequestFile);
-    this.statusRequestFile = null;
-    delete(this.statusFile);
-    this.statusFile = null;
-  }
-
-  protected void delete(final File file) throws Exception {
-    assertEventuallyTrue("deleting " + file, new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        if (file == null) {
-          return true;
-        }
-        try {
-          Files.delete(file.toPath());
-        } catch (IOException e) {
-        }
-        return !file.exists();
-      }
-    }, WAIT_FOR_FILE_DELETION_TIMEOUT, INTERVAL_MILLISECONDS);
-  }
-
-  protected void waitForPidToStop(final int pid, boolean throwOnTimeout) throws Exception {
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(pid);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL_MILLISECONDS);
-  }
-
-  protected void waitForPidToStop(final int pid) throws Exception {
-    waitForPidToStop(pid, true);
-  }
-
-  protected void waitForFileToDelete(final File file, boolean throwOnTimeout) throws Exception {
-    if (file == null) {
-      return;
-    }
-    assertEventuallyTrue("waiting for file " + file + " to delete", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return !file.exists();
-      }
-    }, WAIT_FOR_FILE_DELETION_TIMEOUT, INTERVAL_MILLISECONDS);
-  }
-
-  protected void waitForFileToDelete(final File file) throws Exception {
-    waitForFileToDelete(file, true);
-  }
-
-  protected static int getPid() throws PidUnavailableException {
-    return ProcessUtils.identifyPid();
-  }
-
-  protected InputListener createLoggingListener(final String name, final String header) {
-    return new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        logger.info(new StringBuilder("[").append(header).append("]").append(line).toString());
-      }
-
-      @Override
-      public String toString() {
-        return name;
-      }
-    };
-  }
-
-  protected InputListener createCollectionListener(final String name, final String header,
-      final List<String> lines) {
-    return new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        lines.add(line);
-      }
-
-      @Override
-      public String toString() {
-        return name;
-      }
-    };
-  }
-
-  protected InputListener createExpectedListener(final String name, final String header,
-      final String expected, final AtomicBoolean atomic) {
-    return new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        if (line.contains(expected)) {
-          atomic.set(true);
-        }
-      }
-
-      @Override
-      public String toString() {
-        return name;
-      }
-    };
-  }
-
-  protected void writeGemfireProperties(final Properties gemfireProperties,
-      final File gemfirePropertiesFile) throws IOException {
-    if (!gemfirePropertiesFile.exists()) {
-      gemfireProperties.store(new FileWriter(gemfirePropertiesFile),
-          "Configuration settings for the GemFire Server");
-    }
-  }
-
-  protected int readPid(final File pidFile) throws IOException {
-    BufferedReader reader = null;
-    try {
-      reader = new BufferedReader(new FileReader(pidFile));
-      return Integer.parseInt(StringUtils.trim(reader.readLine()));
-    } finally {
-      IOUtils.close(reader);
-    }
-  }
-
-  protected void writePid(final File pidFile, final int pid) throws IOException {
-    FileWriter writer = new FileWriter(pidFile);
-    writer.write(String.valueOf(pid));
-    writer.write("\n");
-    writer.flush();
-    writer.close();
-  }
-
-  protected void waitForFileToExist(final File file, boolean throwOnTimeout) throws Exception {
-    assertEventuallyTrue("waiting for file " + file + " to exist", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return file.exists();
-      }
-    }, WAIT_FOR_FILE_CREATION_TIMEOUT, INTERVAL_MILLISECONDS);
-  }
-
-  protected void waitForFileToExist(final File file) throws Exception {
-    waitForFileToExist(file, true);
-  }
-
-  protected String getUniqueName() {
-    return getClass().getSimpleName() + "_" + testName.getMethodName();
-  }
-
-  protected static void assertEventuallyTrue(final String message, final Callable<Boolean> callable,
-      final int timeout, final int interval) throws Exception {
-    boolean done = false;
-    for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done =
-        (callable.call())) {
-      Thread.sleep(interval);
-    }
-    assertTrue(message, done);
-  }
-
-  protected static void assertEventuallyFalse(final String message,
-      final Callable<Boolean> callable, final int timeout, final int interval) throws Exception {
-    boolean done = false;
-    for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done =
-        (!callable.call())) {
-      Thread.sleep(interval);
-    }
-    assertTrue(message, done);
-  }
-
-  protected static void disconnectFromDS() {
-    InternalDistributedSystem ids = InternalDistributedSystem.getConnectedInstance();
-    if (ids != null) {
-      ids.disconnect();
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStateTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStateTest.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStateTest.java
new file mode 100755
index 0000000..4b03c92
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStateTest.java
@@ -0,0 +1,224 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.GemFireVersion;
+import org.apache.geode.internal.process.ProcessUtils;
+import org.apache.geode.management.internal.cli.json.GfJsonArray;
+import org.apache.geode.management.internal.cli.json.GfJsonException;
+import org.apache.geode.management.internal.cli.json.GfJsonObject;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link AbstractLauncher.ServiceState}. Tests marshalling of ServiceState to and
+ * from JSON.
+ * 
+ * @since GemFire 7.0
+ */
+@Category(UnitTest.class)
+public class AbstractLauncherServiceStateTest {
+
+  private static String serviceName;
+  private static String name;
+  private static int pid;
+  private static long uptime;
+  private static String workingDirectory;
+  private static List<String> jvmArguments;
+  private static String classpath;
+  private static String gemfireVersion;
+  private static String javaVersion;
+
+  private TestLauncher launcher;
+
+  @Before
+  public void setUp() throws Exception {
+    serviceName = "Test";
+    pid = ProcessUtils.identifyPid();
+    uptime = 123456789;
+    name = AbstractLauncherServiceStateTest.class.getSimpleName();
+    workingDirectory = new File(System.getProperty("user.dir")).getAbsolutePath();
+    jvmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
+    classpath = ManagementFactory.getRuntimeMXBean().getClassPath();
+    gemfireVersion = GemFireVersion.getGemFireVersion();
+    javaVersion = System.getProperty("java.version");
+
+    int port = 12345;
+    InetAddress host = InetAddress.getLocalHost();
+
+    launcher = new TestLauncher(host, port, name);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    serviceName = null;
+    name = null;
+    workingDirectory = null;
+    jvmArguments = null;
+    classpath = null;
+    gemfireVersion = null;
+    javaVersion = null;
+  }
+
+  @Test
+  public void serviceStateCanBeMarshalledToAndFromJson() throws Exception {
+    TestLauncher.TestState status = launcher.status();
+    String json = status.toJson();
+    validateJson(status, json);
+    validateStatus(status, TestLauncher.TestState.fromJson(json));
+  }
+
+  private void validateStatus(final TestLauncher.TestState expected,
+      final TestLauncher.TestState actual) {
+    assertThat(actual.getClasspath()).isEqualTo(expected.getClasspath());
+    assertThat(actual.getGemFireVersion()).isEqualTo(expected.getGemFireVersion());
+    assertThat(actual.getJavaVersion()).isEqualTo(expected.getJavaVersion());
+    assertThat(actual.getJvmArguments()).isEqualTo(expected.getJvmArguments());
+    assertThat(actual.getPid()).isEqualTo(expected.getPid());
+    assertThat(actual.getStatus()).isEqualTo(expected.getStatus());
+    assertThat(actual.getTimestamp()).isEqualTo(expected.getTimestamp());
+    assertThat(actual.getUptime()).isEqualTo(expected.getUptime());
+    assertThat(actual.getWorkingDirectory()).isEqualTo(expected.getWorkingDirectory());
+    assertThat(actual.getHost()).isEqualTo(expected.getHost());
+    assertThat(actual.getPort()).isEqualTo(expected.getPort());
+    assertThat(actual.getMemberName()).isEqualTo(expected.getMemberName());
+  }
+
+  private void validateJson(final TestLauncher.TestState expected, final String json) {
+    TestLauncher.TestState actual = TestLauncher.TestState.fromJson(json);
+    validateStatus(expected, actual);
+  }
+
+  private static class TestLauncher extends AbstractLauncher<String> {
+
+    private final InetAddress bindAddress;
+    private final int port;
+    private final String memberName;
+    private final File logFile;
+
+    TestLauncher(final InetAddress bindAddress, final int port, final String memberName) {
+      this.bindAddress = bindAddress;
+      this.port = port;
+      this.memberName = memberName;
+      this.logFile = new File(memberName + ".log");
+    }
+
+    public TestState status() {
+      return new TestState(Status.ONLINE, null, System.currentTimeMillis(), getId(), pid, uptime,
+          workingDirectory, jvmArguments, classpath, gemfireVersion, javaVersion, getLogFileName(),
+          getBindAddressAsString(), getPortAsString(), name);
+    }
+
+    @Override
+    public void run() {
+      // nothing
+    }
+
+    public String getId() {
+      return getServiceName() + "@" + getBindAddress() + "[" + getPort() + "]";
+    }
+
+    @Override
+    public String getLogFileName() {
+      try {
+        return logFile.getCanonicalPath();
+      } catch (IOException e) {
+        return logFile.getAbsolutePath();
+      }
+    }
+
+    @Override
+    public String getMemberName() {
+      return memberName;
+    }
+
+    @Override
+    public Integer getPid() {
+      return null;
+    }
+
+    @Override
+    public String getServiceName() {
+      return serviceName;
+    }
+
+    InetAddress getBindAddress() {
+      return bindAddress;
+    }
+
+    String getBindAddressAsString() {
+      return bindAddress.getCanonicalHostName();
+    }
+
+    int getPort() {
+      return port;
+    }
+
+    String getPortAsString() {
+      return String.valueOf(getPort());
+    }
+
+    private static class TestState extends ServiceState<String> {
+
+      protected static TestState fromJson(final String json) {
+        try {
+          GfJsonObject gfJsonObject = new GfJsonObject(json);
+
+          Status status = Status.valueOfDescription(gfJsonObject.getString(JSON_STATUS));
+          List<String> jvmArguments = Arrays
+              .asList(GfJsonArray.toStringArray(gfJsonObject.getJSONArray(JSON_JVMARGUMENTS)));
+
+          return new TestState(status, gfJsonObject.getString(JSON_STATUSMESSAGE),
+              gfJsonObject.getLong(JSON_TIMESTAMP), gfJsonObject.getString(JSON_LOCATION),
+              gfJsonObject.getInt(JSON_PID), gfJsonObject.getLong(JSON_UPTIME),
+              gfJsonObject.getString(JSON_WORKINGDIRECTORY), jvmArguments,
+              gfJsonObject.getString(JSON_CLASSPATH), gfJsonObject.getString(JSON_GEMFIREVERSION),
+              gfJsonObject.getString(JSON_JAVAVERSION), gfJsonObject.getString(JSON_LOGFILE),
+              gfJsonObject.getString(JSON_HOST), gfJsonObject.getString(JSON_PORT),
+              gfJsonObject.getString(JSON_MEMBERNAME));
+        } catch (GfJsonException e) {
+          throw new IllegalArgumentException("Unable to create TestState from JSON: " + json);
+        }
+      }
+
+      protected TestState(final Status status, final String statusMessage, final long timestamp,
+          final String location, final Integer pid, final Long uptime,
+          final String workingDirectory, final List<String> jvmArguments, final String classpath,
+          final String gemfireVersion, final String javaVersion, final String logFile,
+          final String host, final String port, final String name) {
+        super(status, statusMessage, timestamp, location, pid, uptime, workingDirectory,
+            jvmArguments, classpath, gemfireVersion, javaVersion, logFile, host, port, name);
+      }
+
+      @Override
+      protected String getServiceName() {
+        return serviceName;
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStatusTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStatusTest.java b/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStatusTest.java
deleted file mode 100755
index 1aa449e..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/AbstractLauncherServiceStatusTest.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.net.InetAddress;
-import java.util.Arrays;
-import java.util.List;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.internal.GemFireVersion;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.management.internal.cli.json.GfJsonArray;
-import org.apache.geode.management.internal.cli.json.GfJsonException;
-import org.apache.geode.management.internal.cli.json.GfJsonObject;
-import org.apache.geode.test.junit.categories.UnitTest;
-
-/**
- * Tests marshaling of ServiceStatus to and from JSON.
- * 
- * @since GemFire 7.0
- */
-@Category(UnitTest.class)
-public class AbstractLauncherServiceStatusTest {
-
-  private static String serviceName;
-  private static InetAddress host;
-  private static int port;
-  private static String name;
-  private static int pid;
-  private static long uptime;
-  private static String workingDirectory;
-  private static List<String> jvmArguments;
-  private static String classpath;
-  private static String gemfireVersion;
-  private static String javaVersion;
-
-  private TestLauncher launcher;
-
-  @Before
-  public void setUp() throws Exception {
-    serviceName = "Test";
-    port = 12345;
-    host = InetAddress.getLocalHost();
-    pid = ProcessUtils.identifyPid();
-    uptime = 123456789;
-    name = AbstractLauncherServiceStatusTest.class.getSimpleName();
-    workingDirectory = new File(System.getProperty("user.dir")).getAbsolutePath();
-    jvmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
-    classpath = ManagementFactory.getRuntimeMXBean().getClassPath();
-    gemfireVersion = GemFireVersion.getGemFireVersion();
-    javaVersion = System.getProperty("java.version");
-
-    this.launcher = new TestLauncher(host, port, name);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    serviceName = null;
-    host = null;
-    name = null;
-    workingDirectory = null;
-    jvmArguments = null;
-    classpath = null;
-    gemfireVersion = null;
-    javaVersion = null;
-  }
-
-  @Test
-  public void testMarshallingTestStatusToAndFromJson() {
-    final TestLauncher.TestState status = this.launcher.status();
-    final String json = status.toJson();
-    validateJson(status, json);
-    validateStatus(status, TestLauncher.TestState.fromJson(json));
-  }
-
-  private void validateStatus(final TestLauncher.TestState expected,
-      final TestLauncher.TestState actual) {
-    assertEquals(expected.getClasspath(), actual.getClasspath());
-    assertEquals(expected.getGemFireVersion(), actual.getGemFireVersion());
-    assertEquals(expected.getJavaVersion(), actual.getJavaVersion());
-    assertEquals(expected.getJvmArguments(), actual.getJvmArguments());
-    assertEquals(expected.getPid(), actual.getPid());
-    assertEquals(expected.getStatus(), actual.getStatus());
-    assertEquals(expected.getTimestamp(), actual.getTimestamp());
-    assertEquals(expected.getUptime(), actual.getUptime());
-    assertEquals(expected.getWorkingDirectory(), actual.getWorkingDirectory());
-    assertEquals(expected.getHost(), actual.getHost());
-    assertEquals(expected.getPort(), actual.getPort());
-    assertEquals(expected.getMemberName(), actual.getMemberName());
-  }
-
-  private void validateJson(final TestLauncher.TestState expected, final String json) {
-    final TestLauncher.TestState actual = TestLauncher.TestState.fromJson(json);
-    validateStatus(expected, actual);
-  }
-
-  private static class TestLauncher extends AbstractLauncher<String> {
-
-    private final InetAddress bindAddress;
-    private final int port;
-    private final String memberName;
-    private final File logFile;
-
-    TestLauncher(InetAddress bindAddress, int port, String memberName) {
-      this.bindAddress = bindAddress;
-      this.port = port;
-      this.memberName = memberName;
-      this.logFile = new File(memberName + ".log");
-    }
-
-    public TestState status() {
-      return new TestState(Status.ONLINE, null, System.currentTimeMillis(), getId(), pid, uptime,
-          workingDirectory, jvmArguments, classpath, gemfireVersion, javaVersion, getLogFileName(),
-          getBindAddressAsString(), getPortAsString(), name);
-    }
-
-    @Override
-    public void run() {}
-
-    public String getId() {
-      return getServiceName() + "@" + getBindAddress() + "[" + getPort() + "]";
-    }
-
-    @Override
-    public String getLogFileName() {
-      try {
-        return this.logFile.getCanonicalPath();
-      } catch (IOException e) {
-        return this.logFile.getAbsolutePath();
-      }
-    }
-
-    @Override
-    public String getMemberName() {
-      return this.memberName;
-    }
-
-    @Override
-    public Integer getPid() {
-      return null;
-    }
-
-    @Override
-    public String getServiceName() {
-      return serviceName;
-    }
-
-    InetAddress getBindAddress() {
-      return this.bindAddress;
-    }
-
-    String getBindAddressAsString() {
-      return this.bindAddress.getCanonicalHostName();
-    }
-
-    int getPort() {
-      return this.port;
-    }
-
-    String getPortAsString() {
-      return String.valueOf(getPort());
-    }
-
-    private static class TestState extends ServiceState<String> {
-
-      protected static TestState fromJson(final String json) {
-        try {
-          final GfJsonObject gfJsonObject = new GfJsonObject(json);
-
-          final Status status = Status.valueOfDescription(gfJsonObject.getString(JSON_STATUS));
-          final List<String> jvmArguments = Arrays
-              .asList(GfJsonArray.toStringArray(gfJsonObject.getJSONArray(JSON_JVMARGUMENTS)));
-
-          return new TestState(status, gfJsonObject.getString(JSON_STATUSMESSAGE),
-              gfJsonObject.getLong(JSON_TIMESTAMP), gfJsonObject.getString(JSON_LOCATION),
-              gfJsonObject.getInt(JSON_PID), gfJsonObject.getLong(JSON_UPTIME),
-              gfJsonObject.getString(JSON_WORKINGDIRECTORY), jvmArguments,
-              gfJsonObject.getString(JSON_CLASSPATH), gfJsonObject.getString(JSON_GEMFIREVERSION),
-              gfJsonObject.getString(JSON_JAVAVERSION), gfJsonObject.getString(JSON_LOGFILE),
-              gfJsonObject.getString(JSON_HOST), gfJsonObject.getString(JSON_PORT),
-              gfJsonObject.getString(JSON_MEMBERNAME));
-        } catch (GfJsonException e) {
-          throw new IllegalArgumentException("Unable to create TestState from JSON: " + json);
-        }
-      }
-
-      protected TestState(final Status status, final String statusMessage, final long timestamp,
-          final String location, final Integer pid, final Long uptime,
-          final String workingDirectory, final List<String> jvmArguments, final String classpath,
-          final String gemfireVersion, final String javaVersion, final String logFile,
-          final String host, final String port, final String name) {
-        super(status, statusMessage, timestamp, location, pid, uptime, workingDirectory,
-            jvmArguments, classpath, gemfireVersion, javaVersion, logFile, host, port, name);
-      }
-
-      @Override
-      protected String getServiceName() {
-        return serviceName;
-      }
-    }
-  }
-
-}


[15/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorStateTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorStateTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorStateTest.java
index 5cb7dea..7ef3ff0 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorStateTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorStateTest.java
@@ -14,14 +14,16 @@
  */
 package org.apache.geode.distributed;
 
-import static com.googlecode.catchexception.CatchException.*;
-import static org.assertj.core.api.Assertions.*;
+import static com.googlecode.catchexception.CatchException.caughtException;
+import static com.googlecode.catchexception.CatchException.verifyException;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
@@ -33,26 +35,45 @@ import org.apache.geode.management.internal.cli.json.GfJsonObject;
 import org.apache.geode.test.junit.categories.UnitTest;
 
 /**
- * Unit tests for LocatorLauncher.LocatorState
+ * Unit tests for {@link LocatorLauncher.LocatorState}.
  */
 @Category(UnitTest.class)
 public class LocatorStateTest {
 
-  private String classpath = "test_classpath";
-  private String gemFireVersion = "test_gemfireversion";
-  private String host = "test_host";
-  private String javaVersion = "test_javaversion";
-  private String jvmArguments = "test_jvmarguments";
-  private String serviceLocation = "test_location";
-  private String logFile = "test_logfile";
-  private String memberName = "test_membername";
-  private Integer pid = 6396;
-  private String port = "test_port";
-  private String statusDescription = Status.NOT_RESPONDING.getDescription();
-  private String statusMessage = "test_statusmessage";
-  private Long timestampTime = 1450728233024L;
-  private Long uptime = 1629L;
-  private String workingDirectory = "test_workingdirectory";
+  private String classpath;
+  private String gemFireVersion;
+  private String host;
+  private String javaVersion;
+  private String jvmArguments;
+  private String serviceLocation;
+  private String logFile;
+  private String memberName;
+  private Integer pid;
+  private String port;
+  private String statusDescription;
+  private String statusMessage;
+  private Long timestampTime;
+  private Long uptime;
+  private String workingDirectory;
+
+  @Before
+  public void before() throws Exception {
+    classpath = "test_classpath";
+    gemFireVersion = "test_gemfireVersion";
+    host = "test_host";
+    javaVersion = "test_javaVersion";
+    jvmArguments = "test_jvmArguments";
+    serviceLocation = "test_location";
+    logFile = "test_logfile";
+    memberName = "test_memberName";
+    pid = 6396;
+    port = "test_port";
+    statusDescription = Status.NOT_RESPONDING.getDescription();
+    statusMessage = "test_statusMessage";
+    timestampTime = 1450728233024L;
+    uptime = 1629L;
+    workingDirectory = "test_workingDirectory";
+  }
 
   @Test
   public void fromJsonWithEmptyStringThrowsIllegalArgumentException() throws Exception {
@@ -65,7 +86,6 @@ public class LocatorStateTest {
     // then: throws IllegalArgumentException with cause of GfJsonException
     assertThat((Exception) caughtException()).isInstanceOf(IllegalArgumentException.class)
         .hasCauseInstanceOf(GfJsonException.class);
-
     assertThat(caughtException().getCause()).isInstanceOf(GfJsonException.class).hasNoCause();
   }
 
@@ -80,7 +100,6 @@ public class LocatorStateTest {
     // then: throws IllegalArgumentException with cause of GfJsonException
     assertThat((Exception) caughtException()).isInstanceOf(IllegalArgumentException.class)
         .hasCauseInstanceOf(GfJsonException.class);
-
     assertThat(caughtException().getCause()).isInstanceOf(GfJsonException.class).hasNoCause();
   }
 
@@ -106,107 +125,53 @@ public class LocatorStateTest {
 
     // then: return valid instance of LocatorState
     assertThat(value).isInstanceOf(LocatorState.class);
-
-    assertThat(value.getClasspath()).isEqualTo(getClasspath());
-    assertThat(value.getGemFireVersion()).isEqualTo(getGemFireVersion());
-    assertThat(value.getHost()).isEqualTo(getHost());
-    assertThat(value.getJavaVersion()).isEqualTo(getJavaVersion());
+    assertThat(value.getClasspath()).isEqualTo(classpath);
+    assertThat(value.getGemFireVersion()).isEqualTo(gemFireVersion);
+    assertThat(value.getHost()).isEqualTo(host);
+    assertThat(value.getJavaVersion()).isEqualTo(javaVersion);
     assertThat(value.getJvmArguments()).isEqualTo(getJvmArguments());
-    assertThat(value.getServiceLocation()).isEqualTo(getServiceLocation());
-    assertThat(value.getLogFile()).isEqualTo(getLogFile());
-    assertThat(value.getMemberName()).isEqualTo(getMemberName());
-    assertThat(value.getPid()).isEqualTo(getPid());
-    assertThat(value.getPort()).isEqualTo(getPort());
-    assertThat(value.getStatus().getDescription()).isEqualTo(getStatusDescription());
-    assertThat(value.getStatusMessage()).isEqualTo(getStatusMessage());
-    assertThat(value.getTimestamp().getTime()).isEqualTo(getTimestampTime());
-    assertThat(value.getUptime()).isEqualTo(getUptime());
-    assertThat(value.getWorkingDirectory()).isEqualTo(getWorkingDirectory());
-  }
-
+    assertThat(value.getLogFile()).isEqualTo(logFile);
+    assertThat(value.getMemberName()).isEqualTo(memberName);
+    assertThat(value.getPid()).isEqualTo(pid);
+    assertThat(value.getPort()).isEqualTo(port);
+    assertThat(value.getServiceLocation()).isEqualTo(serviceLocation);
+    assertThat(value.getStatus().getDescription()).isEqualTo(statusDescription);
+    assertThat(value.getStatusMessage()).isEqualTo(statusMessage);
+    assertThat(value.getTimestamp().getTime()).isEqualTo(timestampTime);
+    assertThat(value.getUptime()).isEqualTo(uptime);
+    assertThat(value.getWorkingDirectory()).isEqualTo(workingDirectory);
+  }
+
+  /**
+   * NOTE: Must be protected for CatchException.
+   */
   protected LocatorState fromJson(final String value) {
     return LocatorState.fromJson(value);
   }
 
-  private String getClasspath() {
-    return this.classpath;
-  }
-
-  private String getGemFireVersion() {
-    return this.gemFireVersion;
-  }
-
-  private String getHost() {
-    return this.host;
-  }
-
-  private String getJavaVersion() {
-    return this.javaVersion;
-  }
-
   private List<String> getJvmArguments() {
-    List<String> list = new ArrayList<String>();
-    list.add(this.jvmArguments);
+    List<String> list = new ArrayList<>();
+    list.add(jvmArguments);
     return list;
   }
 
-  private String getServiceLocation() {
-    return this.serviceLocation;
-  }
-
-  private String getLogFile() {
-    return this.logFile;
-  }
-
-  private String getMemberName() {
-    return this.memberName;
-  }
-
-  private Integer getPid() {
-    return this.pid;
-  }
-
-  private String getPort() {
-    return this.port;
-  }
-
-  private String getStatusDescription() {
-    return this.statusDescription;
-  }
-
-  private String getStatusMessage() {
-    return this.statusMessage;
-  }
-
-  private Long getTimestampTime() {
-    return this.timestampTime;
-  }
-
-  private Long getUptime() {
-    return this.uptime;
-  }
-
-  private String getWorkingDirectory() {
-    return this.workingDirectory;
-  }
-
   private String createStatusJson() {
-    final Map<String, Object> map = new HashMap<String, Object>();
-    map.put(ServiceState.JSON_CLASSPATH, getClasspath());
-    map.put(ServiceState.JSON_GEMFIREVERSION, getGemFireVersion());
-    map.put(ServiceState.JSON_HOST, getHost());
-    map.put(ServiceState.JSON_JAVAVERSION, getJavaVersion());
+    Map<String, Object> map = new HashMap<>();
+    map.put(ServiceState.JSON_CLASSPATH, classpath);
+    map.put(ServiceState.JSON_GEMFIREVERSION, gemFireVersion);
+    map.put(ServiceState.JSON_HOST, host);
+    map.put(ServiceState.JSON_JAVAVERSION, javaVersion);
     map.put(ServiceState.JSON_JVMARGUMENTS, getJvmArguments());
-    map.put(ServiceState.JSON_LOCATION, getServiceLocation());
-    map.put(ServiceState.JSON_LOGFILE, getLogFile());
-    map.put(ServiceState.JSON_MEMBERNAME, getMemberName());
-    map.put(ServiceState.JSON_PID, getPid());
-    map.put(ServiceState.JSON_PORT, getPort());
-    map.put(ServiceState.JSON_STATUS, getStatusDescription());
-    map.put(ServiceState.JSON_STATUSMESSAGE, getStatusMessage());
-    map.put(ServiceState.JSON_TIMESTAMP, getTimestampTime());
-    map.put(ServiceState.JSON_UPTIME, getUptime());
-    map.put(ServiceState.JSON_WORKINGDIRECTORY, getWorkingDirectory());
+    map.put(ServiceState.JSON_LOCATION, serviceLocation);
+    map.put(ServiceState.JSON_LOGFILE, logFile);
+    map.put(ServiceState.JSON_MEMBERNAME, memberName);
+    map.put(ServiceState.JSON_PID, pid);
+    map.put(ServiceState.JSON_PORT, port);
+    map.put(ServiceState.JSON_STATUS, statusDescription);
+    map.put(ServiceState.JSON_STATUSMESSAGE, statusMessage);
+    map.put(ServiceState.JSON_TIMESTAMP, timestampTime);
+    map.put(ServiceState.JSON_UPTIME, uptime);
+    map.put(ServiceState.JSON_WORKINGDIRECTORY, workingDirectory);
     return new GfJsonObject(map).toString();
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/MockServerLauncherCacheProvider.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/MockServerLauncherCacheProvider.java b/geode-core/src/test/java/org/apache/geode/distributed/MockServerLauncherCacheProvider.java
deleted file mode 100644
index 768cc89..0000000
--- a/geode-core/src/test/java/org/apache/geode/distributed/MockServerLauncherCacheProvider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.distributed;
-
-import java.util.Properties;
-
-import org.apache.geode.cache.Cache;
-
-public class MockServerLauncherCacheProvider implements ServerLauncherCacheProvider {
-
-  private static Cache cache;
-
-  public static Cache getCache() {
-    return cache;
-  }
-
-  public static void setCache(Cache cache) {
-    MockServerLauncherCacheProvider.cache = cache;
-  }
-
-  @Override
-  public Cache createCache(Properties gemfireProperties, ServerLauncher serverLauncher) {
-    return cache;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerCommand.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerCommand.java
new file mode 100644
index 0000000..ca1bfd9
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerCommand.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.geode.distributed.ServerLauncher.Command;
+
+public class ServerCommand {
+
+  private String javaPath;
+  private List<String> jvmArguments = new ArrayList<>();
+  private String classPath;
+  private Command command;
+  private String name;
+  private boolean disableDefaultServer;
+  private boolean force;
+  private int serverPort;
+
+  public ServerCommand() {
+    // do nothing
+  }
+
+  public ServerCommand(final UsesServerCommand user) {
+    this.javaPath = user.getJavaPath();
+    this.jvmArguments = user.getJvmArguments();
+    this.classPath = user.getClassPath();
+    this.name = user.getName();
+    this.disableDefaultServer = user.getDisableDefaultServer();
+    this.command = Command.START;
+  }
+
+  public ServerCommand withJavaPath(final String javaPath) {
+    this.javaPath = javaPath;
+    return this;
+  }
+
+  public ServerCommand withJvmArguments(final List<String> jvmArguments) {
+    this.jvmArguments = jvmArguments;
+    return this;
+  }
+
+  public ServerCommand addJvmArgument(final String arg) {
+    this.jvmArguments.add(arg);
+    return this;
+  }
+
+  public ServerCommand withClassPath(final String classPath) {
+    this.classPath = classPath;
+    return this;
+  }
+
+  public ServerCommand withCommand(final Command command) {
+    this.command = command;
+    return this;
+  }
+
+  public ServerCommand withName(final String name) {
+    this.name = name;
+    return this;
+  }
+
+  public ServerCommand disableDefaultServer() {
+    return disableDefaultServer(true);
+  }
+
+  public ServerCommand disableDefaultServer(final boolean value) {
+    this.disableDefaultServer = value;
+    return this;
+  }
+
+  public ServerCommand force() {
+    return force(true);
+  }
+
+  public ServerCommand force(final boolean value) {
+    this.force = value;
+    return this;
+  }
+
+  public ServerCommand withServerPort(final int serverPort) {
+    this.serverPort = serverPort;
+    return disableDefaultServer(false);
+  }
+
+  public List<String> create() {
+    List<String> cmd = new ArrayList<>();
+    cmd.add(javaPath);
+    cmd.addAll(jvmArguments);
+    cmd.add("-cp");
+    cmd.add(classPath);
+    cmd.add(ServerLauncher.class.getName());
+    cmd.add(command.getName());
+    cmd.add(name);
+    if (disableDefaultServer) {
+      cmd.add("--disable-default-server");
+    }
+    if (force) {
+      cmd.add("--force");
+    }
+    cmd.add("--redirect-output");
+    if (serverPort > 0) {
+      cmd.add("--server-port=" + serverPort);
+    }
+    return cmd;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherBuilderTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherBuilderTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherBuilderTest.java
new file mode 100644
index 0000000..b7a6fcd
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherBuilderTest.java
@@ -0,0 +1,845 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import joptsimple.OptionException;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.cache.server.CacheServer;
+import org.apache.geode.distributed.ServerLauncher.Builder;
+import org.apache.geode.distributed.ServerLauncher.Command;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link ServerLauncher.Builder}. Extracted from {@link ServerLauncherTest}.
+ */
+@Category(UnitTest.class)
+public class ServerLauncherBuilderTest {
+
+  private InetAddress localHost;
+  private String localHostName;
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+  @Before
+  public void before() throws Exception {
+    localHost = InetAddress.getLocalHost();
+    localHostName = localHost.getCanonicalHostName();
+  }
+
+  @Test
+  public void defaultCommandIsUnspecified() throws Exception {
+    assertThat(Builder.DEFAULT_COMMAND).isEqualTo(Command.UNSPECIFIED);
+  }
+
+  @Test
+  public void getCommandReturnsUnspecifiedByDefault() throws Exception {
+    assertThat(new Builder().getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void getCriticalHeapPercentageReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getCriticalHeapPercentage()).isNull();
+  }
+
+  @Test
+  public void getEvictionHeapPercentageReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getEvictionHeapPercentage()).isNull();
+  }
+
+  @Test
+  public void getForceReturnsFalseByDefault() {
+    assertThat(new Builder().getForce()).isFalse();
+  }
+
+  @Test
+  public void getHostNameForClientsReturnsNullByDefault() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.getHostNameForClients()).isNull();
+  }
+
+  @Test
+  public void getMaxConnectionsReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getMaxConnections()).isNull();
+  }
+
+  @Test
+  public void getMaxMessageCountReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getMaxMessageCount()).isNull();
+  }
+
+  @Test
+  public void getMaxThreadsReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getMaxThreads()).isNull();
+  }
+
+  @Test
+  public void getMessageTimeToLiveReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getMessageTimeToLive()).isNull();
+  }
+
+  @Test
+  public void getMemberNameReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getMemberName()).isNull();
+  }
+
+  @Test
+  public void getPidReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getPid()).isNull();
+  }
+
+  @Test
+  public void getServerBindAddressReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getServerBindAddress()).isNull();
+  }
+
+  @Test
+  public void getServerPortReturnsDefaultPortByDefault() throws Exception {
+    assertThat(new Builder().getServerPort()).isEqualTo(Integer.valueOf(CacheServer.DEFAULT_PORT));
+  }
+
+  @Test
+  public void getSocketBufferSizeReturnsNullByDefault() throws Exception {
+    assertThat(new Builder().getSocketBufferSize()).isNull();
+  }
+
+  @Test
+  public void setCommandReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setCommand(Command.STATUS)).isSameAs(builder);
+  }
+
+  @Test
+  public void setCriticalHeapPercentageReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setCriticalHeapPercentage(55.5f)).isSameAs(builder);
+  }
+
+  @Test
+  public void setEvictionHeapPercentageReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setEvictionHeapPercentage(55.55f)).isSameAs(builder);
+  }
+
+  @Test
+  public void setForceReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setForce(true)).isSameAs(builder);
+  }
+
+  @Test
+  public void setHostNameForClientsReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setHostNameForClients("Pegasus")).isSameAs(builder);
+  }
+
+  @Test
+  public void setMaxConnectionsReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setMaxConnections(1000)).isSameAs(builder);
+  }
+
+  @Test
+  public void setMaxMessageCountReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setMaxMessageCount(50)).isSameAs(builder);
+  }
+
+  @Test
+  public void setMaxThreadsReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setMaxThreads(16)).isSameAs(builder);
+  }
+
+  @Test
+  public void setMemberNameReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setMemberName("serverOne")).isSameAs(builder);
+  }
+
+  @Test
+  public void setPidReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setPid(0)).isSameAs(builder);
+  }
+
+  @Test
+  public void setServerBindAddressReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setServerBindAddress(null)).isSameAs(builder);
+  }
+
+  @Test
+  public void setServerPortReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setServerPort(null)).isSameAs(builder);
+  }
+
+  @Test
+  public void setMessageTimeToLiveReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setMessageTimeToLive(30000)).isSameAs(builder);
+  }
+
+  @Test
+  public void setSocketBufferSizeReturnsBuilderInstance() throws Exception {
+    Builder builder = new Builder();
+
+    assertThat(builder.setSocketBufferSize(32768)).isSameAs(builder);
+  }
+
+  @Test
+  public void setCommandWithNullResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    new Builder().setCommand(null);
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void setCommandToStatusResultsInStatus() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setCommand(Command.STATUS);
+
+    assertThat(builder.getCommand()).isEqualTo(Command.STATUS);
+  }
+
+  @Test
+  public void setCriticalHeapPercentageToPercentileUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setCriticalHeapPercentage(55.5f);
+
+    assertThat(builder.getCriticalHeapPercentage().floatValue()).isEqualTo(55.5f);
+  }
+
+  @Test
+  public void setCriticalHeapPercentageToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setCriticalHeapPercentage(null);
+
+    assertThat(builder.getCriticalHeapPercentage()).isNull();
+  }
+
+  @Test
+  public void setCriticalHeapPercentageAbove100ThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setCriticalHeapPercentage(100.01f))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setCriticalHeapPercentageBelowZeroThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setCriticalHeapPercentage(-0.01f))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setEvictionHeapPercentageToPercentileUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setEvictionHeapPercentage(55.55f);
+
+    assertThat(builder.getEvictionHeapPercentage().floatValue()).isEqualTo(55.55f);
+  }
+
+  @Test
+  public void setEvictionHeapPercentageToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setEvictionHeapPercentage(null);
+
+    assertThat(builder.getEvictionHeapPercentage()).isNull();
+  }
+
+  @Test
+  public void setEvictionHeapPercentageAboveO100ThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setEvictionHeapPercentage(101.0f))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setEvictionHeapPercentageBelowZeroThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setEvictionHeapPercentage(-10.0f))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setForceToTrueUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setForce(true);
+
+    assertThat(builder.getForce()).isTrue();
+  }
+
+  @Test
+  public void setHostNameForClientsToStringUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setHostNameForClients("Pegasus");
+
+    assertThat(builder.getHostNameForClients()).isEqualTo("Pegasus");
+  }
+
+  @Test
+  public void setHostNameForClientsToBlankStringThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setHostNameForClients(" "))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setHostNameForClientsToEmptyStringThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setHostNameForClients(""))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setHostNameForClientsToNullThrowsIllegalArgumentException() {
+    assertThatThrownBy(() -> new Builder().setHostNameForClients(null))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMaxConnectionsToPositiveIntegerUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMaxConnections(1000);
+
+    assertThat(builder.getMaxConnections().intValue()).isEqualTo(1000);
+  }
+
+  @Test
+  public void setMaxConnectionsToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMaxConnections(null);
+
+    assertThat(builder.getMaxConnections()).isNull();
+  }
+
+  @Test
+  public void setMaxConnectionsToNegativeValueThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setMaxConnections(-10))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMaxMessageCountToPositiveIntegerUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMaxMessageCount(50);
+
+    assertThat(builder.getMaxMessageCount().intValue()).isEqualTo(50);
+  }
+
+  @Test
+  public void setMaxMessageCountToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMaxMessageCount(null);
+
+    assertThat(builder.getMaxMessageCount()).isNull();
+  }
+
+  @Test
+  public void setMaxMessageCountToZeroResultsInIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setMaxMessageCount(0))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMaxThreadsToPositiveIntegerUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMaxThreads(16);
+
+    assertThat(builder.getMaxThreads().intValue()).isEqualTo(16);
+  }
+
+  @Test
+  public void setMaxThreadsToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMaxThreads(null);
+
+    assertThat(builder.getMaxThreads()).isNull();
+  }
+
+  @Test
+  public void setMaxThreadsToNegativeValueThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setMaxThreads(-4))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMemberNameToStringUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMemberName("serverOne");
+
+    assertThat(builder.getMemberName()).isEqualTo("serverOne");
+  }
+
+  @Test
+  public void setMemberNameToBlankStringThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setMemberName("  "))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMemberNameToEmptyStringThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setMemberName(""))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMemberNameToNullStringThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setMemberName(null))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setMessageTimeToLiveToPositiveIntegerUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMessageTimeToLive(30000);
+
+    assertThat(builder.getMessageTimeToLive().intValue()).isEqualTo(30000);
+  }
+
+  @Test
+  public void setMessageTimeToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setMessageTimeToLive(null);
+
+    assertThat(builder.getMessageTimeToLive()).isNull();
+  }
+
+  @Test
+  public void setMessageTimeToLiveToZeroThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setMessageTimeToLive(0))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setPidToZeroOrGreaterUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setPid(0);
+    assertThat(builder.getPid().intValue()).isEqualTo(0);
+
+    builder.setPid(1);
+    assertThat(builder.getPid().intValue()).isEqualTo(1);
+
+    builder.setPid(1024);
+    assertThat(builder.getPid().intValue()).isEqualTo(1024);
+
+    builder.setPid(12345);
+    assertThat(builder.getPid().intValue()).isEqualTo(12345);
+  }
+
+  @Test
+  public void setPidToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setPid(null);
+
+    assertThat(builder.getPid()).isNull();
+  }
+
+  @Test
+  public void setPidToNegativeValueThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setPid(-1)).isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setServerBindAddressToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setServerBindAddress(null);
+
+    assertThat(builder.getServerBindAddress()).isNull();
+  }
+
+  @Test
+  public void setServerBindAddressToEmptyStringResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setServerBindAddress("");
+
+    assertThat(builder.getServerBindAddress()).isNull();
+  }
+
+  @Test
+  public void setServerBindAddressToBlankStringResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setServerBindAddress("  ");
+
+    assertThat(builder.getServerBindAddress()).isNull();
+  }
+
+  @Test
+  public void setServerBindAddressToCanonicalLocalHostUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setServerBindAddress(localHostName);
+
+    assertThat(builder.getServerBindAddress()).isEqualTo(localHost);
+  }
+
+  @Test
+  public void setServerBindAddressToLocalHostNameUsesValue() throws Exception {
+    String host = InetAddress.getLocalHost().getHostName();
+
+    Builder builder = new Builder().setServerBindAddress(host);
+
+    assertThat(builder.getServerBindAddress()).isEqualTo(localHost);
+  }
+
+  @Test
+  public void setServerBindAddressToUnknownHostThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setServerBindAddress("badHostName.badCompany.com"))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasCauseInstanceOf(UnknownHostException.class);
+  }
+
+  @Test
+  public void setServerBindAddressToNonLocalHostThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setServerBindAddress("yahoo.com"))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setServerPortToNullResultsInDefaultPort() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setServerPort(null);
+
+    assertThat(builder.getServerPort()).isEqualTo(Integer.valueOf(CacheServer.DEFAULT_PORT));
+  }
+
+  @Test
+  public void setServerPortToZeroOrGreaterUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setServerPort(0);
+    assertThat(builder.getServerPort().intValue()).isEqualTo(0);
+
+    builder.setServerPort(1);
+    assertThat(builder.getServerPort().intValue()).isEqualTo(1);
+
+    builder.setServerPort(80);
+    assertThat(builder.getServerPort().intValue()).isEqualTo(80);
+
+    builder.setServerPort(1024);
+    assertThat(builder.getServerPort().intValue()).isEqualTo(1024);
+
+    builder.setServerPort(65535);
+    assertThat(builder.getServerPort().intValue()).isEqualTo(65535);
+  }
+
+  @Test
+  public void setServerPortAboveMaxValueThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setServerPort(65536))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setServerPortToNegativeValueThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setServerPort(-1))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void setSocketBufferSizeToPositiveIntegerUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setSocketBufferSize(32768);
+
+    assertThat(builder.getSocketBufferSize().intValue()).isEqualTo(32768);
+  }
+
+  @Test
+  public void setSocketBufferSizeToNullResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.setSocketBufferSize(null);
+
+    assertThat(builder.getSocketBufferSize()).isNull();
+  }
+
+  @Test
+  public void setSocketBufferSizeToNegativeValueThrowsIllegalArgumentException() throws Exception {
+    assertThatThrownBy(() -> new Builder().setSocketBufferSize(-8192))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void parseArgumentsWithForceSetsForceToTrue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseArguments("start", "--force");
+
+    assertThat(builder.getForce()).isTrue();
+  }
+
+  @Test
+  public void parseArgumentsWithNonNumericPortThrowsIllegalArgumentException() {
+    assertThatThrownBy(
+        () -> new Builder().parseArguments("start", "server1", "--server-port", "oneTwoThree"))
+            .isInstanceOf(IllegalArgumentException.class).hasCauseInstanceOf(OptionException.class);
+  }
+
+  @Test
+  public void parseArgumentsParsesValuesSeparatedWithCommas() throws Exception {
+    // given: fresh builder
+    Builder builder = new Builder();
+
+    // when: parsing comma-separated arguments
+    builder.parseArguments("start", "serverOne", "--assign-buckets", "--disable-default-server",
+        "--debug", "--force", "--rebalance", "--redirect-output", "--pid", "1234",
+        "--server-bind-address", InetAddress.getLocalHost().getHostAddress(), "--server-port",
+        "11235", "--hostname-for-clients", "192.168.99.100");
+
+    // then: getters should return parsed values
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+    assertThat(builder.getMemberName()).isEqualTo("serverOne");
+    assertThat(builder.getHostNameForClients()).isEqualTo("192.168.99.100");
+    assertThat(builder.getAssignBuckets()).isTrue();
+    assertThat(builder.getDisableDefaultServer()).isTrue();
+    assertThat(builder.getDebug()).isTrue();
+    assertThat(builder.getForce()).isTrue();
+    assertThat(builder.getHelp()).isFalse();
+    assertThat(builder.getRebalance()).isTrue();
+    assertThat(builder.getRedirectOutput()).isTrue();
+    assertThat(builder.getPid().intValue()).isEqualTo(1234);
+    assertThat(builder.getServerBindAddress()).isEqualTo(InetAddress.getLocalHost());
+    assertThat(builder.getServerPort().intValue()).isEqualTo(11235);
+  }
+
+  @Test
+  public void parseArgumentsParsesValuesSeparatedWithEquals() throws Exception {
+    // given: fresh builder
+    Builder builder = new Builder();
+
+    // when: parsing equals-separated arguments
+    builder.parseArguments("start", "serverOne", "--assign-buckets", "--disable-default-server",
+        "--debug", "--force", "--rebalance", "--redirect-output", "--pid=1234",
+        "--server-bind-address=" + InetAddress.getLocalHost().getHostAddress(),
+        "--server-port=11235", "--hostname-for-clients=192.168.99.100");
+
+    // then: getters should return parsed values
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+    assertThat(builder.getMemberName()).isEqualTo("serverOne");
+    assertThat(builder.getHostNameForClients()).isEqualTo("192.168.99.100");
+    assertThat(builder.getAssignBuckets()).isTrue();
+    assertThat(builder.getDisableDefaultServer()).isTrue();
+    assertThat(builder.getDebug()).isTrue();
+    assertThat(builder.getForce()).isTrue();
+    assertThat(builder.getHelp()).isFalse();
+    assertThat(builder.getRebalance()).isTrue();
+    assertThat(builder.getRedirectOutput()).isTrue();
+    assertThat(builder.getPid().intValue()).isEqualTo(1234);
+    assertThat(builder.getServerBindAddress()).isEqualTo(InetAddress.getLocalHost());
+    assertThat(builder.getServerPort().intValue()).isEqualTo(11235);
+  }
+
+  @Test
+  public void parseCommandWithNullStringArrayResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand((String[]) null);
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void parseCommandWithEmptyStringArrayResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand(); // empty String array
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void parseCommandWithStartResultsInStartCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand(Command.START.getName());
+
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+  }
+
+  @Test
+  public void parseCommandWithStatusResultsInStatusCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("Status");
+
+    assertThat(builder.getCommand()).isEqualTo(Command.STATUS);
+  }
+
+  @Test
+  public void parseCommandWithMixedCaseResultsInCorrectCase() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("sToP");
+
+    assertThat(builder.getCommand()).isEqualTo(Command.STOP);
+  }
+
+  @Test
+  public void parseCommandWithTwoCommandsWithSwitchesUsesFirstCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("--opt", "START", "-o", Command.STATUS.getName());
+
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+  }
+
+  @Test
+  public void parseCommandWithTwoCommandsWithoutSwitchesUsesFirstCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("START", Command.STATUS.getName());
+
+    assertThat(builder.getCommand()).isEqualTo(Command.START);
+  }
+
+  @Test
+  public void parseCommandWithBadInputResultsInDefaultCommand() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseCommand("badCommandName", "--start", "stat");
+
+    assertThat(builder.getCommand()).isEqualTo(Builder.DEFAULT_COMMAND);
+  }
+
+  @Test
+  public void parseMemberNameWithNullStringArrayResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName((String[]) null);
+
+    assertThat(builder.getMemberName()).isNull();
+  }
+
+  @Test
+  public void parseMemberNameWithEmptyStringArrayResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName(); // empty String array
+
+    assertThat(builder.getMemberName()).isNull();
+  }
+
+  @Test
+  public void parseMemberNameWithCommandAndOptionsResultsInNull() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName(Command.START.getName(), "--opt", "-o");
+
+    assertThat(builder.getMemberName()).isNull();
+  }
+
+  @Test
+  public void parseMemberNameWithStringUsesValue() throws Exception {
+    Builder builder = new Builder();
+
+    builder.parseMemberName("memberOne");
+
+    assertThat(builder.getMemberName()).isEqualTo("memberOne");
+  }
+
+  @Test
+  public void buildCreatesServerLauncherWithBuilderValues() throws Exception {
+    ServerLauncher launcher = new Builder().setCommand(Command.STOP).setAssignBuckets(true)
+        .setForce(true).setMemberName("serverOne").setRebalance(true)
+        .setServerBindAddress(InetAddress.getLocalHost().getHostAddress()).setServerPort(11235)
+        .setCriticalHeapPercentage(90.0f).setEvictionHeapPercentage(75.0f).setMaxConnections(100)
+        .setMaxMessageCount(512).setMaxThreads(8).setMessageTimeToLive(120000)
+        .setSocketBufferSize(32768).build();
+
+    assertThat(launcher.getCommand()).isEqualTo(Command.STOP);
+    assertThat(launcher.getMemberName()).isEqualTo("serverOne");
+    assertThat(launcher.getServerBindAddress()).isEqualTo(InetAddress.getLocalHost());
+    assertThat(launcher.getServerPort().intValue()).isEqualTo(11235);
+    assertThat(launcher.getCriticalHeapPercentage().floatValue()).isEqualTo(90.0f);
+    assertThat(launcher.getEvictionHeapPercentage().floatValue()).isEqualTo(75.0f);
+    assertThat(launcher.getMaxConnections().intValue()).isEqualTo(100);
+    assertThat(launcher.getMaxMessageCount().intValue()).isEqualTo(512);
+    assertThat(launcher.getMaxThreads().intValue()).isEqualTo(8);
+    assertThat(launcher.getMessageTimeToLive().intValue()).isEqualTo(120000);
+    assertThat(launcher.getSocketBufferSize().intValue()).isEqualTo(32768);
+    assertThat(launcher.isAssignBuckets()).isTrue();
+    assertThat(launcher.isDebugging()).isFalse();
+    assertThat(launcher.isDisableDefaultServer()).isFalse();
+    assertThat(launcher.isForcing()).isTrue();
+    assertThat(launcher.isHelping()).isFalse();
+    assertThat(launcher.isRebalancing()).isTrue();
+    assertThat(launcher.isRunning()).isFalse();
+  }
+
+  @Test
+  public void buildUsesMemberNameSetInApiProperties() throws Exception {
+    ServerLauncher launcher =
+        new Builder().setCommand(ServerLauncher.Command.START).set(NAME, "serverABC").build();
+
+    assertThat(launcher.getMemberName()).isNull();
+    assertThat(launcher.getProperties().getProperty(NAME)).isEqualTo("serverABC");
+  }
+
+  @Test
+  public void buildUsesMemberNameSetInSystemProperties() throws Exception {
+    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + NAME, "serverXYZ");
+
+    ServerLauncher launcher = new Builder().setCommand(ServerLauncher.Command.START).build();
+
+    assertThat(launcher.getMemberName()).isNull();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTest.java
index d3c1200..6ce9be6 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTest.java
@@ -17,14 +17,20 @@ package org.apache.geode.distributed;
 import static com.googlecode.catchexception.apis.BDDCatchException.caughtException;
 import static com.googlecode.catchexception.apis.BDDCatchException.when;
 import static org.apache.geode.distributed.ConfigurationProperties.NAME;
+import static org.apache.geode.distributed.DistributedSystem.PROPERTIES_FILE_PROPERTY;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.apache.geode.internal.cache.AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.BDDAssertions.then;
 
-import org.apache.geode.distributed.ServerLauncher.Builder;
-import org.apache.geode.distributed.ServerLauncher.Command;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.i18n.LocalizedStrings;
-import org.apache.geode.test.junit.categories.IntegrationTest;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.InetAddress;
+import java.util.Properties;
+
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.contrib.java.lang.system.RestoreSystemProperties;
@@ -32,19 +38,20 @@ import org.junit.experimental.categories.Category;
 import org.junit.rules.TemporaryFolder;
 import org.junit.rules.TestName;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.net.InetAddress;
-import java.util.Properties;
+import org.apache.geode.distributed.ServerLauncher.Builder;
+import org.apache.geode.distributed.ServerLauncher.Command;
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
- * Integration tests for ServerLauncher class. These tests may require file system and/or network
- * I/O.
+ * Integration tests for using {@link ServerLauncher} as an in-process API within an existing JVM.
  */
 @Category(IntegrationTest.class)
 public class ServerLauncherIntegrationTest {
 
+  private static final String CURRENT_DIRECTORY = System.getProperty("user.dir");
+
   @Rule
   public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
 
@@ -55,222 +62,242 @@ public class ServerLauncherIntegrationTest {
   public final TestName testName = new TestName();
 
   @Test
-  public void testBuildWithManyArguments() throws Exception {
-    // given
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
-
-    // when
-    ServerLauncher launcher = new Builder().setCommand(Command.STOP).setAssignBuckets(true)
-        .setForce(true).setMemberName("serverOne").setRebalance(true)
-        .setServerBindAddress(InetAddress.getLocalHost().getHostAddress()).setServerPort(11235)
-        .setWorkingDirectory(rootFolder).setCriticalHeapPercentage(90.0f)
-        .setEvictionHeapPercentage(75.0f).setMaxConnections(100).setMaxMessageCount(512)
-        .setMaxThreads(8).setMessageTimeToLive(120000).setSocketBufferSize(32768).build();
-
-    // then
-    assertThat(launcher).isNotNull();
-    assertThat(launcher.isAssignBuckets()).isTrue();
-    assertThat(launcher.isDebugging()).isFalse();
-    assertThat(launcher.isDisableDefaultServer()).isFalse();
-    assertThat(launcher.isForcing()).isTrue();
-    assertThat(launcher.isHelping()).isFalse();
-    assertThat(launcher.isRebalancing()).isTrue();
-    assertThat(launcher.isRunning()).isFalse();
-    assertThat(launcher.getCommand()).isEqualTo(Command.STOP);
-    assertThat(launcher.getMemberName()).isEqualTo("serverOne");
-    assertThat(launcher.getServerBindAddress()).isEqualTo(InetAddress.getLocalHost());
-    assertThat(launcher.getServerPort().intValue()).isEqualTo(11235);
-    assertThat(launcher.getWorkingDirectory()).isEqualTo(rootFolder);
-    assertThat(launcher.getCriticalHeapPercentage().floatValue()).isEqualTo(90.0f);
-    assertThat(launcher.getEvictionHeapPercentage().floatValue()).isEqualTo(75.0f);
-    assertThat(launcher.getMaxConnections().intValue()).isEqualTo(100);
-    assertThat(launcher.getMaxMessageCount().intValue()).isEqualTo(512);
-    assertThat(launcher.getMaxThreads().intValue()).isEqualTo(8);
-    assertThat(launcher.getMessageTimeToLive().intValue()).isEqualTo(120000);
-    assertThat(launcher.getSocketBufferSize().intValue()).isEqualTo(32768);
+  public void buildWithMemberNameSetInGemFireProperties() throws Exception {
+    // given: gemfire.properties containing a name
+    givenGemFirePropertiesFile(withMemberName());
+
+    // when: starting with null MemberName
+    ServerLauncher launcher = new Builder().setCommand(Command.START).build();
+
+    // then: name in gemfire.properties file should be used for MemberName
+    assertThat(launcher.getMemberName()).isNull(); // name will be read during start()
   }
 
   @Test
-  public void testBuilderParseArgumentsWithValuesSeparatedWithCommas() throws Exception {
-    // given a new builder and a directory
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
+  public void buildWithoutMemberNameThrowsIllegalStateException() throws Exception {
+    // given: gemfire.properties with no name
+    givenGemFirePropertiesFile(withoutMemberName());
+
+    // when: no MemberName is specified
+    when(new Builder().setCommand(Command.START)).build();
+
+    // then: throw IllegalStateException
+    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class)
+        .hasMessage(memberNameValidationErrorMessage());
+  }
+
+  @Test
+  public void buildWithWorkingDirectoryNotEqualToCurrentDirectoryThrowsIllegalStateException()
+      throws Exception {
+    // given: using LocatorLauncher in-process
+
+    // when: setting WorkingDirectory to non-current directory
+    when(new Builder().setCommand(Command.START).setMemberName("memberOne")
+        .setWorkingDirectory(getWorkingDirectoryPath())).build();
+
+    // then: throw IllegalStateException
+    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class)
+        .hasMessage(workingDirectoryOptionNotValidErrorMessage());
+  }
+
+  @Test
+  public void parseArgumentsParsesValuesSeparatedByCommas() throws Exception {
+    // given: a new builder
     Builder builder = new Builder();
 
     // when: parsing many arguments
-    builder.parseArguments("start", "serverOne", "--assign-buckets", "--disable-default-server",
-        "--debug", "--force", "--rebalance", "--redirect-output", "--dir", rootFolder, "--pid",
-        "1234", "--server-bind-address", InetAddress.getLocalHost().getHostAddress(),
-        "--server-port", "11235", "--hostname-for-clients", "192.168.99.100");
+    builder.parseArguments("start", "memberOne", "--server-bind-address",
+        InetAddress.getLocalHost().getHostAddress(), "--dir", getWorkingDirectoryPath(),
+        "--hostname-for-clients", "Tucows", "--pid", "1234", "--server-port", "11235",
+        "--redirect-output", "--force", "--debug");
 
     // then: the getters should return properly parsed values
     assertThat(builder.getCommand()).isEqualTo(Command.START);
-    assertThat(builder.getMemberName()).isEqualTo("serverOne");
-    assertThat(builder.getHostNameForClients()).isEqualTo("192.168.99.100");
-    assertThat(builder.getAssignBuckets()).isTrue();
-    assertThat(builder.getDisableDefaultServer()).isTrue();
     assertThat(builder.getDebug()).isTrue();
     assertThat(builder.getForce()).isTrue();
-    assertThat(builder.getHelp()).isFalse();
-    assertThat(builder.getRebalance()).isTrue();
-    assertThat(builder.getRedirectOutput()).isTrue();
-    assertThat(builder.getWorkingDirectory()).isEqualTo(rootFolder);
+    assertThat(builder.getHostNameForClients()).isEqualTo("Tucows");
     assertThat(builder.getPid().intValue()).isEqualTo(1234);
     assertThat(builder.getServerBindAddress()).isEqualTo(InetAddress.getLocalHost());
     assertThat(builder.getServerPort().intValue()).isEqualTo(11235);
+    assertThat(builder.getRedirectOutput()).isTrue();
+    assertThat(builder.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
   @Test
-  public void testBuilderParseArgumentsWithValuesSeparatedWithEquals() throws Exception {
-    // given a new builder and a directory
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
+  public void parseArgumentsParsesValuesSeparatedByEquals() throws Exception {
+    // given: a new builder
     Builder builder = new Builder();
 
-    // when: parsing many arguments
-    builder.parseArguments("start", "serverOne", "--assign-buckets", "--disable-default-server",
-        "--debug", "--force", "--rebalance", "--redirect-output", "--dir=" + rootFolder,
-        "--pid=1234", "--server-bind-address=" + InetAddress.getLocalHost().getHostAddress(),
-        "--server-port=11235", "--hostname-for-clients=192.168.99.100");
+    // when: parsing arguments with values separated by equals
+    builder.parseArguments("start", "--dir=" + getWorkingDirectoryPath(),
+        "--server-port=" + "12345", "memberOne");
 
     // then: the getters should return properly parsed values
     assertThat(builder.getCommand()).isEqualTo(Command.START);
-    assertThat(builder.getMemberName()).isEqualTo("serverOne");
-    assertThat(builder.getHostNameForClients()).isEqualTo("192.168.99.100");
-    assertThat(builder.getAssignBuckets()).isTrue();
-    assertThat(builder.getDisableDefaultServer()).isTrue();
-    assertThat(builder.getDebug()).isTrue();
-    assertThat(builder.getForce()).isTrue();
+    assertThat(builder.getDebug()).isFalse();
+    assertThat(builder.getForce()).isFalse();
     assertThat(builder.getHelp()).isFalse();
-    assertThat(builder.getRebalance()).isTrue();
-    assertThat(builder.getRedirectOutput()).isTrue();
-    assertThat(builder.getWorkingDirectory()).isEqualTo(rootFolder);
-    assertThat(builder.getPid().intValue()).isEqualTo(1234);
-    assertThat(builder.getServerBindAddress()).isEqualTo(InetAddress.getLocalHost());
-    assertThat(builder.getServerPort().intValue()).isEqualTo(11235);
+    assertThat(builder.getHostNameForClients()).isNull();
+    assertThat(builder.getMemberName()).isEqualTo("memberOne");
+    assertThat(builder.getPid()).isNull();
+    assertThat(builder.getServerBindAddress()).isNull();
+    assertThat(builder.getServerPort().intValue()).isEqualTo(12345);
+    assertThat(builder.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
   @Test
-  public void testBuildWithMemberNameSetInGemFirePropertiesOnStart() throws Exception {
-    // given: gemfire.properties with a name
-    Properties gemfireProperties = new Properties();
-    gemfireProperties.setProperty(NAME, "server123");
-    useGemFirePropertiesFileInTemporaryFolder(DistributionConfig.GEMFIRE_PREFIX + "properties",
-        gemfireProperties);
+  public void getWorkingDirectoryReturnsCurrentDirectoryByDefault() throws Exception {
+    // given:
 
-    // when: starting with null MemberName
-    ServerLauncher launcher = new Builder().setCommand(Command.START).build();
+    // when: not setting WorkingDirectory
 
-    // then: name in gemfire.properties file should be used for MemberName
-    assertThat(launcher).isNotNull();
-    assertThat(launcher.getCommand()).isEqualTo(Command.START);
-    assertThat(launcher.getMemberName()).isNull();
+    // then: getDirectory returns default
+    assertThat(new Builder().getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
   }
 
   @Test
-  public void testBuildWithNoMemberNameOnStart() throws Exception {
-    // given: gemfire.properties with no name
-    useGemFirePropertiesFileInTemporaryFolder(DistributionConfig.GEMFIRE_PREFIX + "properties",
-        new Properties());
+  public void setWorkingDirectoryToNullUsesCurrentDirectory() throws Exception {
+    // given: a new builder
+    Builder builder = new Builder();
 
-    // when: no MemberName is specified
-    when(new Builder().setCommand(Command.START)).build();
+    // when: setting WorkingDirectory to null
+    assertThat(builder.setWorkingDirectory(null)).isSameAs(builder);
 
-    // then: throw IllegalStateException
-    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class)
-        .hasMessage(LocalizedStrings.Launcher_Builder_MEMBER_NAME_VALIDATION_ERROR_MESSAGE
-            .toLocalizedString("Server"));
+    // then: getDirectory returns default
+    assertThat(builder.getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
   }
 
   @Test
-  public void testBuilderSetAndGetWorkingDirectory() throws Exception {
-    // given: a new builder and a directory
-    String rootFolder = this.temporaryFolder.getRoot().getCanonicalPath();
+  public void setWorkingDirectoryToEmptyStringUsesCurrentDirectory() throws Exception {
+    // given: a new builder
     Builder builder = new Builder();
 
-    // when: not setting WorkingDirectory
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(ServerLauncher.DEFAULT_WORKING_DIRECTORY);
-
-    // when: setting WorkingDirectory to null
-    assertThat(builder.setWorkingDirectory(null)).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
-
     // when: setting WorkingDirectory to empty string
     assertThat(builder.setWorkingDirectory("")).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
+
+    // then: getDirectory returns default
+    assertThat(builder.getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
+  }
+
+  @Test
+  public void setWorkingDirectoryToBlankStringUsesCurrentDirectory() throws Exception {
+    // given: a new builder
+    Builder builder = new Builder();
 
     // when: setting WorkingDirectory to white space
     assertThat(builder.setWorkingDirectory("  ")).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
+
+    // then: getDirectory returns default
+    assertThat(builder.getWorkingDirectory()).isEqualTo(CURRENT_DIRECTORY);
+  }
+
+  @Test
+  public void setWorkingDirectoryToExistingDirectory() throws Exception {
+    // given: a new builder
+    Builder builder = new Builder();
 
     // when: setting WorkingDirectory to a directory
-    assertThat(builder.setWorkingDirectory(rootFolder)).isSameAs(builder);
-    // then: getWorkingDirectory returns that directory
-    assertThat(builder.getWorkingDirectory()).isEqualTo(rootFolder);
+    assertThat(builder.setWorkingDirectory(getWorkingDirectoryPath())).isSameAs(builder);
 
-    // when: setting WorkingDirectory to null (again)
-    assertThat(builder.setWorkingDirectory(null)).isSameAs(builder);
-    // then: getWorkingDirectory returns default
-    assertThat(builder.getWorkingDirectory()).isEqualTo(AbstractLauncher.DEFAULT_WORKING_DIRECTORY);
+    // then: getDirectory returns that directory
+    assertThat(builder.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
   @Test
-  public void testBuilderSetWorkingDirectoryToFile() throws Exception {
+  public void setWorkingDirectoryToExistingFileThrowsIllegalArgumentException() throws Exception {
     // given: a file instead of a directory
-    File tmpFile = this.temporaryFolder.newFile();
+    File nonDirectory = temporaryFolder.newFile();
 
     // when: setting WorkingDirectory to that file
-    when(new Builder()).setWorkingDirectory(tmpFile.getAbsolutePath());
+    when(new Builder()).setWorkingDirectory(nonDirectory.getCanonicalPath());
 
     // then: throw IllegalArgumentException
-    then(caughtException())
-        .hasMessage(LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
-            .toLocalizedString("Server"))
-        .hasCause(new FileNotFoundException(tmpFile.getAbsolutePath()));
+    then(caughtException()).isExactlyInstanceOf(IllegalArgumentException.class)
+        .hasMessage(workingDirectoryNotFoundErrorMessage())
+        .hasCause(new FileNotFoundException(nonDirectory.getCanonicalPath()));
   }
 
   @Test
-  public void testBuildSetWorkingDirectoryToNonCurrentDirectoryOnStart() throws Exception {
-    // given: using ServerLauncher in-process
-
-    // when: setting WorkingDirectory to non-current directory
-    when(new Builder().setCommand(Command.START).setMemberName("serverOne")
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath())).build();
+  public void setWorkingDirectoryToNonExistingDirectory() throws Exception {
+    // given:
 
-    // then: throw IllegalStateException
-    then(caughtException()).isExactlyInstanceOf(IllegalStateException.class).hasMessage(
-        LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE
-            .toLocalizedString("Server"));
-  }
-
-  @Test
-  public void testBuilderSetWorkingDirectoryToNonExistingDirectory() {
     // when: setting WorkingDirectory to non-existing directory
     when(new Builder()).setWorkingDirectory("/path/to/non_existing/directory");
 
     // then: throw IllegalArgumentException
-    then(caughtException())
-        .hasMessage(LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
-            .toLocalizedString("Server"))
+    then(caughtException()).isExactlyInstanceOf(IllegalArgumentException.class)
+        .hasMessage(workingDirectoryNotFoundErrorMessage())
         .hasCause(new FileNotFoundException("/path/to/non_existing/directory"));
   }
 
+  @Test
+  public void serverPortCanBeOverriddenBySystemProperty() throws Exception {
+    // given: overridden default port
+    int overriddenPort = AvailablePortHelper.getRandomAvailableTCPPort();
+    System.setProperty(TEST_OVERRIDE_DEFAULT_PORT_PROPERTY, String.valueOf(overriddenPort));
+
+    // when: creating new ServerLauncher
+    ServerLauncher launcher = new Builder().build();
+
+    // then: server port should be the overridden default port
+    assertThat(launcher.getServerPort()).isEqualTo(overriddenPort);
+  }
+
+  private String memberNameValidationErrorMessage() {
+    return LocalizedStrings.Launcher_Builder_MEMBER_NAME_VALIDATION_ERROR_MESSAGE
+        .toLocalizedString("Server");
+  }
+
+  private String workingDirectoryOptionNotValidErrorMessage() {
+    return LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_OPTION_NOT_VALID_ERROR_MESSAGE
+        .toLocalizedString("Server");
+  }
+
+  private String workingDirectoryNotFoundErrorMessage() {
+    return LocalizedStrings.Launcher_Builder_WORKING_DIRECTORY_NOT_FOUND_ERROR_MESSAGE
+        .toLocalizedString("Server");
+  }
+
+  private File getWorkingDirectory() {
+    return temporaryFolder.getRoot();
+  }
+
+  private String getWorkingDirectoryPath() {
+    try {
+      return temporaryFolder.getRoot().getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private Properties withoutMemberName() {
+    return new Properties();
+  }
+
+  private Properties withMemberName() {
+    Properties properties = new Properties();
+    properties.setProperty(NAME, "locator123");
+    return properties;
+  }
+
   /**
    * Creates a gemfire properties file in temporaryFolder:
-   * <li>creates <code>fileName</code> in <code>temporaryFolder</code>
-   * <li>sets "gemfirePropertyFile" system property
-   * <li>writes <code>gemfireProperties</code> to the file
+   * <ol>
+   * <li>creates gemfire.properties in <code>temporaryFolder</code></li>
+   * <li>writes config to the file</li>
+   * <li>sets "gemfirePropertyFile" system property</li>
+   * </ol>
    */
-  private void useGemFirePropertiesFileInTemporaryFolder(final String fileName,
-      final Properties gemfireProperties) throws Exception {
-    File propertiesFile = new File(this.temporaryFolder.getRoot().getCanonicalPath(), fileName);
-    System.setProperty(DistributedSystem.PROPERTIES_FILE_PROPERTY,
-        propertiesFile.getCanonicalPath());
-
-    gemfireProperties.store(new FileWriter(propertiesFile, false), this.testName.getMethodName());
-    assertThat(propertiesFile.isFile()).isTrue();
-    assertThat(propertiesFile.exists()).isTrue();
+  private void givenGemFirePropertiesFile(final Properties config) {
+    try {
+      String name = GEMFIRE_PREFIX + "properties";
+      File file = new File(getWorkingDirectory(), name);
+      config.store(new FileWriter(file, false), testName.getMethodName());
+      assertThat(file).isFile().exists();
+
+      System.setProperty(PROPERTIES_FILE_PROPERTY, file.getCanonicalPath());
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTestCase.java
new file mode 100755
index 0000000..ed443f5
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherIntegrationTestCase.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.distributed.ConfigurationProperties.CACHE_XML_FILE;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPorts;
+import static org.apache.geode.internal.cache.AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.UncheckedIOException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.ErrorCollector;
+
+import org.apache.geode.cache.DataPolicy;
+import org.apache.geode.cache.Scope;
+import org.apache.geode.distributed.AbstractLauncher.Status;
+import org.apache.geode.distributed.ServerLauncher.Builder;
+import org.apache.geode.distributed.ServerLauncher.ServerState;
+import org.apache.geode.internal.cache.xmlcache.CacheCreation;
+import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator;
+import org.apache.geode.internal.cache.xmlcache.RegionAttributesCreation;
+import org.apache.geode.internal.process.ProcessType;
+
+/**
+ * Abstract base class for integration tests of {@link ServerLauncher}.
+ *
+ * @since GemFire 8.0
+ */
+public abstract class ServerLauncherIntegrationTestCase extends LauncherIntegrationTestCase {
+
+  protected volatile int defaultServerPort;
+  protected volatile int nonDefaultServerPort;
+  protected volatile int unusedServerPort;
+  protected volatile ServerLauncher launcher;
+  protected volatile String workingDirectory;
+  protected volatile File cacheXmlFile;
+
+  @Rule
+  public ErrorCollector errorCollector = new ErrorCollector();
+
+  @Before
+  public void setUpAbstractServerLauncherIntegrationTestCase() throws Exception {
+    System.setProperty(GEMFIRE_PREFIX + MCAST_PORT, Integer.toString(0));
+
+    workingDirectory = temporaryFolder.getRoot().getCanonicalPath();
+
+    int[] ports = getRandomAvailableTCPPorts(3);
+    defaultServerPort = ports[0];
+    nonDefaultServerPort = ports[1];
+    unusedServerPort = ports[2];
+    System.setProperty(TEST_OVERRIDE_DEFAULT_PORT_PROPERTY, String.valueOf(defaultServerPort));
+  }
+
+  @After
+  public void tearDownAbstractServerLauncherIntegrationTestCase() throws Exception {
+    if (launcher != null) {
+      launcher.stop();
+    }
+  }
+
+  @Override
+  protected ProcessType getProcessType() {
+    return ProcessType.SERVER;
+  }
+
+  protected ServerLauncher awaitStart(final ServerLauncher launcher) {
+    await().atMost(2, MINUTES).until(() -> assertThat(isLauncherOnline()).isTrue());
+    return launcher;
+  }
+
+  protected ServerLauncher awaitStart(final Builder builder) {
+    launcher = builder.build();
+    assertThat(launcher.start().getStatus()).isEqualTo(Status.ONLINE);
+    return awaitStart(launcher);
+  }
+
+  /**
+   * Returns a new Builder with helpful defaults for safe testing. If you need a Builder in a test
+   * without any of these defaults then simply use {@code new Builder()} instead.
+   */
+  protected Builder newBuilder() {
+    return new Builder().setMemberName(getUniqueName()).setRedirectOutput(true)
+        .setWorkingDirectory(getWorkingDirectoryPath()).set(LOG_LEVEL, "config")
+        .set(MCAST_PORT, "0");
+  }
+
+  protected ServerLauncher givenServerLauncher() {
+    return givenServerLauncher(newBuilder());
+  }
+
+  protected ServerLauncher givenServerLauncher(final Builder builder) {
+    return builder.build();
+  }
+
+  protected ServerLauncher givenRunningServer() {
+    return givenRunningServer(newBuilder());
+  }
+
+  protected ServerLauncher givenRunningServer(final Builder builder) {
+    return awaitStart(builder);
+  }
+
+  protected ServerLauncher startServer() {
+    return awaitStart(newBuilder());
+  }
+
+  protected ServerLauncher startServer(final Builder builder) {
+    return awaitStart(builder);
+  }
+
+  protected File givenCacheXmlFileWithServerPort(final int cacheXmlPort) {
+    try {
+      cacheXmlFile = writeCacheXml(cacheXmlPort);
+      System.setProperty(CACHE_XML_FILE, cacheXmlFile.getCanonicalPath());
+      return cacheXmlFile;
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected File givenCacheXmlFile() {
+    try {
+      cacheXmlFile = writeCacheXml();
+      System.setProperty(CACHE_XML_FILE, cacheXmlFile.getCanonicalPath());
+      return cacheXmlFile;
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  protected File getCacheXmlFile() {
+    return cacheXmlFile;
+  }
+
+  protected String getCacheXmlFilePath() {
+    try {
+      return cacheXmlFile.getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private File writeCacheXml(final int serverPort) throws IOException {
+    CacheCreation creation = new CacheCreation();
+    RegionAttributesCreation attrs = new RegionAttributesCreation(creation);
+    attrs.setScope(Scope.DISTRIBUTED_ACK);
+    attrs.setDataPolicy(DataPolicy.REPLICATE);
+    creation.createRegion(getUniqueName(), attrs);
+    creation.addCacheServer().setPort(serverPort);
+
+    File cacheXmlFile = new File(getWorkingDirectory(), getUniqueName() + ".xml");
+    PrintWriter pw = new PrintWriter(new FileWriter(cacheXmlFile), true);
+    CacheXmlGenerator.generate(creation, pw);
+    pw.close();
+
+    return cacheXmlFile;
+  }
+
+  private File writeCacheXml() throws IOException {
+    CacheCreation creation = new CacheCreation();
+    RegionAttributesCreation attrs = new RegionAttributesCreation(creation);
+    attrs.setScope(Scope.DISTRIBUTED_ACK);
+    attrs.setDataPolicy(DataPolicy.REPLICATE);
+    creation.createRegion(getUniqueName(), attrs);
+    creation.addCacheServer();
+
+    File cacheXmlFile = new File(getWorkingDirectory(), getUniqueName() + ".xml");
+    PrintWriter pw = new PrintWriter(new FileWriter(cacheXmlFile), true);
+    CacheXmlGenerator.generate(creation, pw);
+    pw.close();
+
+    return cacheXmlFile;
+  }
+
+  private boolean isLauncherOnline() {
+    ServerState serverState = launcher.status();
+    assertNotNull(serverState);
+    return Status.ONLINE.equals(serverState.getStatus());
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalFileIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalFileIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalFileIntegrationTest.java
index 0955465..84545f4 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalFileIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherLocalFileIntegrationTest.java
@@ -14,20 +14,19 @@
  */
 package org.apache.geode.distributed;
 
-import static org.junit.Assert.*;
+import static org.assertj.core.api.Assertions.assertThat;
 
-import org.junit.After;
 import org.junit.Before;
-import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
 import org.apache.geode.internal.process.ProcessControllerFactory;
 import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
- * Subclass of ServerLauncherLocalDUnitTest which forces the code to not find the Attach API which
- * is in the JDK tools.jar. As a result ServerLauncher ends up using the FileProcessController
- * implementation.
+ * Integration tests for using {@link ServerLauncher} as an in-process API within an existing JVM.
+ *
+ * Sets {@link ProcessControllerFactory#PROPERTY_DISABLE_ATTACH_API} to force {@code ServerLauncher}
+ * to use the FileProcessController implementation.
  *
  * @since GemFire 8.0
  */
@@ -35,17 +34,8 @@ import org.apache.geode.test.junit.categories.IntegrationTest;
 public class ServerLauncherLocalFileIntegrationTest extends ServerLauncherLocalIntegrationTest {
 
   @Before
-  public final void setUpServerLauncherLocalFileTest() throws Exception {
+  public void setUpServerLauncherLocalFileTest() throws Exception {
     System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true");
-  }
-
-  @After
-  public final void tearDownServerLauncherLocalFileTest() throws Exception {}
-
-  @Override
-  @Test
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertFalse(factory.isAttachAPIFound());
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isFalse();
   }
 }


[13/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTest.java
index d59cde1..733a108 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTest.java
@@ -14,1451 +14,304 @@
  */
 package org.apache.geode.distributed;
 
+import static org.apache.geode.distributed.AbstractLauncher.Status.NOT_RESPONDING;
+import static org.apache.geode.distributed.AbstractLauncher.Status.ONLINE;
+import static org.apache.geode.distributed.AbstractLauncher.Status.STOPPED;
 import static org.apache.geode.distributed.ConfigurationProperties.CACHE_XML_FILE;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.lang.management.ManagementFactory;
+import java.net.BindException;
 import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
 
-import org.junit.Ignore;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.cache.DataPolicy;
-import org.apache.geode.cache.Scope;
-import org.apache.geode.distributed.AbstractLauncher.Status;
 import org.apache.geode.distributed.ServerLauncher.Builder;
 import org.apache.geode.distributed.ServerLauncher.ServerState;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.AvailablePort;
-import org.apache.geode.internal.AvailablePortHelper;
-import org.apache.geode.internal.ExitCode;
 import org.apache.geode.internal.GemFireVersion;
-import org.apache.geode.internal.cache.AbstractCacheServer;
-import org.apache.geode.internal.cache.xmlcache.CacheCreation;
-import org.apache.geode.internal.cache.xmlcache.CacheXmlGenerator;
-import org.apache.geode.internal.cache.xmlcache.RegionAttributesCreation;
-import org.apache.geode.internal.logging.InternalLogWriter;
-import org.apache.geode.internal.logging.LocalLogWriter;
-import org.apache.geode.internal.net.SocketCreatorFactory;
-import org.apache.geode.internal.process.PidUnavailableException;
 import org.apache.geode.internal.process.ProcessControllerFactory;
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.test.junit.categories.FlakyTest;
 import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.apache.geode.test.process.ProcessWrapper;
 
 /**
- * Integration tests for launching a Server in a forked process.
+ * Integration tests for using {@code ServerLauncher} as an application main in a forked JVM.
  *
- * @see org.apache.geode.distributed.AbstractLauncher
- * @see org.apache.geode.distributed.ServerLauncher
- * @see org.apache.geode.distributed.ServerLauncher.Builder
- * @see org.apache.geode.distributed.ServerLauncher.ServerState
- * @see org.apache.geode.internal.AvailablePortHelper
  * @since GemFire 8.0
  */
 @Category(IntegrationTest.class)
-public class ServerLauncherRemoteIntegrationTest
-    extends AbstractServerLauncherRemoteIntegrationTestCase {
+public class ServerLauncherRemoteIntegrationTest extends ServerLauncherRemoteIntegrationTestCase {
 
-  @Test
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertTrue(factory.isAttachAPIFound());
+  @Before
+  public void setUpServerLauncherRemoteIntegrationTest() throws Exception {
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isTrue();
   }
 
   @Test
-  @Ignore("TRAC bug #52304: test is broken and needs to be reworked")
-  public void testRunningServerOutlivesForkingProcess() throws Throwable {
-    // launch ServerLauncherForkingProcess which then launches server
-
-    // final List<String> command = new ArrayList<String>();
-    // command.add(new File(new File(System.getProperty("java.home"), "bin"),
-    // "java").getCanonicalPath());
-    // command.add("-cp");
-    // command.add(System.getProperty("java.class.path"));
-    // command.add(ServerLauncherDUnitTest.class.getName().concat("$").concat(ServerLauncherForkingProcess.class.getSimpleName()));
-    //
-    // process = new ProcessBuilder(command).directory(temporaryFolder.getRoot()).start();
-    // assertNotNull(process);
-    // processOutReader = new ProcessStreamReader(process.getInputStream(), createListener("sysout",
-    // getUniqueName() + "#sysout")).start();
-    // processErrReader = new ProcessStreamReader(process.getErrorStream(), createListener("syserr",
-    // getUniqueName() + "#syserr")).start();
-
-    @SuppressWarnings("unused")
-    File file = new File(this.temporaryFolder.getRoot(),
-        ServerLauncherForkingProcess.class.getSimpleName().concat(".log"));
-    // -logger.info("log file is " + file);
-
-    final ProcessWrapper pw =
-        new ProcessWrapper.Builder().mainClass(ServerLauncherForkingProcess.class).build();
-    pw.execute(null, this.temporaryFolder.getRoot()).waitFor(true);
-    // logger.info("[testRunningServerOutlivesForkingProcess] ServerLauncherForkingProcess output
-    // is:\n\n"+pw.getOutput());
-
-    // // create waiting thread since waitFor does not have a timeout
-    // Thread waiting = new Thread(new Runnable() {
-    // @Override
-    // public void run() {
-    // try {
-    // assertIndexDetailsEquals(0, process.waitFor());
-    // } catch (InterruptedException e) {
-    // logger.error("Interrupted while waiting for process", e);
-    // }
-    // }
-    // });
-
-    // // start waiting thread and join to it for timeout
-    // try {
-    // waiting.start();
-    // waiting.join(TIMEOUT_MILLISECONDS);
-    // assertFalse("ServerLauncherForkingProcess took too long and caused timeout",
-    // waiting.isAlive());
-    //
-    // } catch (Throwable e) {
-    // logger.error(e);
-    // if (failure == null) {
-    // failure = e;
-    // }
-    // } finally {
-    // if (waiting.isAlive()) {
-    // waiting.interrupt();
-    // }
-    // }
-
-    // wait for server to start
-    int pid = 0;
-    final String serverName = ServerLauncherForkingProcess.class.getSimpleName() + "_server";
-    final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart(dirLauncher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = serverName + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // validate the status
-      final ServerState actualStatus = dirLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath(),
-          actualStatus.getWorkingDirectory());
-      assertEquals(getJvmArguments(), actualStatus.getJvmArguments());
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(
-          this.temporaryFolder.getRoot().getCanonicalPath() + File.separator + serverName + ".log",
-          actualStatus.getLogFile());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(serverName, actualStatus.getMemberName());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startCreatesPidFile() throws Exception {
+    startServer();
+
+    assertThat(getPidFile()).exists();
   }
 
   @Test
-  public void testStartCreatesPidFile() throws Throwable {
-    // build and start the server
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // check the status
-      final ServerState serverState = this.launcher.status();
-      assertNotNull(serverState);
-      assertEquals(Status.ONLINE, serverState.getStatus());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void pidFileContainsServerPid() throws Exception {
+    startServer();
+
+    assertThatPidIsAlive(getServerPid());
   }
 
   @Test
-  public void testStartDeletesStaleControlFiles() throws Throwable {
-    // create existing control files
-    this.stopRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getStopRequestFileName());
-    this.stopRequestFile.createNewFile();
-    assertTrue(this.stopRequestFile.exists());
-
-    this.statusRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getStatusRequestFileName());
-    this.statusRequestFile.createNewFile();
-    assertTrue(this.statusRequestFile.exists());
-
-    this.statusFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getStatusFileName());
-    this.statusFile.createNewFile();
-    assertTrue(this.statusFile.exists());
-
-    // build and start the server
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for server to start
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate stale control files were deleted
-      waitForFileToDelete(this.stopRequestFile);
-      waitForFileToDelete(this.statusRequestFile);
-      waitForFileToDelete(this.statusFile);
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startCreatesLogFile() throws Exception {
+    startServer();
+
+    assertThat(getLogFile()).exists();
   }
 
-  @Category(FlakyTest.class) // GEODE-721: random ports (setup overriding default port),
-                             // TemporaryFolder
   @Test
-  public void testStartOverwritesStalePidFile() throws Throwable {
-    // create existing pid file
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-    writePid(this.pidFile, Integer.MAX_VALUE);
-
-    // build and start the server
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertFalse(pid == Integer.MAX_VALUE);
-
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startDeletesStaleControlFiles() throws Exception {
+    File stopRequestFile = givenControlFile(getStopRequestFileName());
+    File statusRequestFile = givenControlFile(getStatusRequestFileName());
+    File statusFile = givenControlFile(getStatusFileName());
+
+    startServer();
+
+    assertDeletionOf(stopRequestFile);
+    assertDeletionOf(statusRequestFile);
+    assertDeletionOf(statusFile);
   }
 
   /**
-   * Confirms fix for #47778.
+   * This test takes > 1 minute to run in {@link ServerLauncherRemoteFileIntegrationTest}.
    */
   @Test
-  public void testStartUsingDisableDefaultServerLeavesPortFree() throws Throwable {
-    assertTrue(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-    // build and start the server
-    final List<String> jvmArguments = getJvmArguments();
-    jvmArguments.add(
-        "-D" + AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY + "=" + this.serverPort);
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for server to start
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // verify server did not a port
-      assertTrue(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-      final ServerState status = this.launcher.status();
-      final String portString = status.getPort();
-      assertEquals("Port should be \"\" instead of " + portString, "", portString);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startOverwritesStalePidFile() throws Exception {
+    givenPidFile(fakePid);
+
+    startServer();
+
+    assertThat(getServerPid()).isNotEqualTo(fakePid);
   }
 
   @Test
-  public void testStartUsingDisableDefaultServerSkipsPortCheck() throws Throwable {
-    // make serverPort in use
-    this.socket = SocketCreatorFactory
-        .createNonDefaultInstance(false, false, null, null, System.getProperties())
-        .createServerSocket(this.serverPort, 50, null, -1);
-    assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-    // build and start the server
-    final List<String> jvmArguments = getJvmArguments();
-    jvmArguments.add(
-        "-D" + AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY + "=" + this.serverPort);
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for server to start
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      final ServerState status = this.launcher.status();
-      final String portString = status.getPort();
-      assertEquals("Port should be \"\" instead of " + portString, "", portString);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // verify port is still in use
-    this.errorCollector.checkThat(
-        AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET), is(equalTo(false)));
+  public void startWithDisableDefaultServerDoesNotUseDefaultPort() throws Exception {
+    givenServerPortIsFree(defaultServerPort);
+
+    startServer(withDisableDefaultServer());
+
+    assertThatServerPortIsFree(defaultServerPort);
   }
 
-  @Category(FlakyTest.class) // GEODE-764: random ports, BindException, forks JVM, uses
-                             // ErrorCollector
   @Test
-  public void testStartUsingForceOverwritesExistingPidFile() throws Throwable {
-    // create existing pid file
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-    final int otherPid = getPid();
-    assertTrue("Pid " + otherPid + " should be alive", ProcessUtils.isProcessAlive(otherPid));
-    writePid(this.pidFile, otherPid);
-
-    // build and start the server
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-    command.add("--force");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for server to start
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertTrue(pid != otherPid);
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithDisableDefaultServerSucceedsWhenDefaultPortInUse() throws Exception {
+    givenServerPortInUse(defaultServerPort);
+
+    startServer(withDisableDefaultServer());
+
+    assertThatServerPortIsInUseBySocket(defaultServerPort);
   }
 
   /**
-   * Confirms fix for #47665.
+   * This test takes > 1 minute to run in {@link ServerLauncherRemoteFileIntegrationTest}.
    */
   @Test
-  public void testStartUsingServerPortInUseFails() throws Throwable {
-    // make serverPort in use
-    this.socket = SocketCreatorFactory
-        .createNonDefaultInstance(false, false, null, null, System.getProperties())
-        .createServerSocket(this.serverPort, 50, null, -1);
-    assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--redirect-output");
-    command.add("--server-port=" + this.serverPort);
-
-    String expectedString = "java.net.BindException";
-    AtomicBoolean outputContainedExpectedString = new AtomicBoolean();
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).inputListener(createExpectedListener("sysout",
-            getUniqueName() + "#sysout", expectedString, outputContainedExpectedString))
-        .build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).inputListener(createExpectedListener("syserr",
-            getUniqueName() + "#syserr", expectedString, outputContainedExpectedString))
-        .build().start();
-
-    // wait for server to start and fail
-    final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      int code = this.process.waitFor();
-      assertEquals("Expected exit code 1 but was " + code, 1, code);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // check the status
-      final ServerState serverState = dirLauncher.status();
-      assertNotNull(serverState);
-      assertEquals(Status.NOT_RESPONDING, serverState.getStatus());
-
-      final String logFileName = getUniqueName() + ".log";
-      assertFalse("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // if the following fails, then the SHORTER_TIMEOUT is too short for slow machines
-    // or this test needs to use MainLauncher in ProcessWrapper
-
-    // validate that output contained BindException
-    this.errorCollector.checkThat(outputContainedExpectedString.get(), is(equalTo(true)));
-
-    // just in case the launcher started...
-    ServerState status = null;
-    try {
-      status = dirLauncher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
-
-    try {
-      assertEquals(getExpectedStopStatusForNotRunning(), status.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithForceOverwritesExistingPidFile() throws Exception {
+    givenPidFile(localPid);
+
+    startServer(withForce());
+
+    assertThatPidIsAlive(getServerPid());
+    assertThat(getServerPid()).isNotEqualTo(localPid);
   }
 
-  /**
-   * Confirms part of fix for #47664
-   */
   @Test
-  public void testStartUsingServerPortOverridesCacheXml() throws Throwable {
-    // generate two free ports
-    final int[] freeTCPPorts = AvailablePortHelper.getRandomAvailableTCPPorts(2);
-
-    // write out cache.xml with one port
-    final CacheCreation creation = new CacheCreation();
-    final RegionAttributesCreation attrs = new RegionAttributesCreation(creation);
-    attrs.setScope(Scope.DISTRIBUTED_ACK);
-    attrs.setDataPolicy(DataPolicy.REPLICATE);
-    creation.createRegion(getUniqueName(), attrs);
-    creation.addCacheServer().setPort(freeTCPPorts[0]);
-
-    File cacheXmlFile = new File(this.temporaryFolder.getRoot(), getUniqueName() + ".xml");
-    final PrintWriter pw = new PrintWriter(new FileWriter(cacheXmlFile), true);
-    CacheXmlGenerator.generate(creation, pw);
-    pw.close();
-
-    // launch server and specify a different port
-    final List<String> jvmArguments = getJvmArguments();
-    jvmArguments.add("-D" + DistributionConfig.GEMFIRE_PREFIX + "" + CACHE_XML_FILE + "="
-        + cacheXmlFile.getCanonicalPath());
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--redirect-output");
-    command.add("--server-port=" + freeTCPPorts[1]);
-
-    String expectedString = "java.net.BindException";
-    AtomicBoolean outputContainedExpectedString = new AtomicBoolean();
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).inputListener(createExpectedListener("sysout",
-            getUniqueName() + "#sysout", expectedString, outputContainedExpectedString))
-        .build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).inputListener(createExpectedListener("syserr",
-            getUniqueName() + "#syserr", expectedString, outputContainedExpectedString))
-        .build().start();
-
-    // wait for server to start up
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // verify server used --server-port instead of default or port in cache.xml
-      assertTrue(AvailablePort.isPortAvailable(freeTCPPorts[0], AvailablePort.SOCKET));
-      assertFalse(AvailablePort.isPortAvailable(freeTCPPorts[1], AvailablePort.SOCKET));
-
-      ServerState status = this.launcher.status();
-      String portString = status.getPort();
-      int port = Integer.valueOf(portString);
-      assertEquals("Port should be " + freeTCPPorts[1] + " instead of " + port, freeTCPPorts[1],
-          port);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-      waitForFileToDelete(this.pidFile);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithServerPortInUseFailsWithBindException() throws Exception {
+    givenServerPortInUse(nonDefaultServerPort);
+
+    startServerShouldFail(withServerPort(nonDefaultServerPort));
+
+    assertThatServerThrew(BindException.class);
   }
 
-  /**
-   * Confirms part of fix for #47664
-   */
   @Test
-  public void testStartUsingServerPortUsedInsteadOfDefaultCacheXml() throws Throwable {
-    // write out cache.xml with one port
-    final CacheCreation creation = new CacheCreation();
-    final RegionAttributesCreation attrs = new RegionAttributesCreation(creation);
-    attrs.setScope(Scope.DISTRIBUTED_ACK);
-    attrs.setDataPolicy(DataPolicy.REPLICATE);
-    creation.createRegion(getUniqueName(), attrs);
-    creation.addCacheServer();
-
-    File cacheXmlFile = new File(this.temporaryFolder.getRoot(), getUniqueName() + ".xml");
-    final PrintWriter pw = new PrintWriter(new FileWriter(cacheXmlFile), true);
-    CacheXmlGenerator.generate(creation, pw);
-    pw.close();
-
-    // launch server and specify a different port
-    final List<String> jvmArguments = getJvmArguments();
-    jvmArguments.add("-D" + DistributionConfig.GEMFIRE_PREFIX + "" + CACHE_XML_FILE + "="
-        + cacheXmlFile.getCanonicalPath());
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--redirect-output");
-    command.add("--server-port=" + this.serverPort);
-
-    final String expectedString = "java.net.BindException";
-    final AtomicBoolean outputContainedExpectedString = new AtomicBoolean();
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).inputListener(createExpectedListener("sysout",
-            getUniqueName() + "#sysout", expectedString, outputContainedExpectedString))
-        .build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).inputListener(createExpectedListener("syserr",
-            getUniqueName() + "#syserr", expectedString, outputContainedExpectedString))
-        .build().start();
-
-    // wait for server to start up
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // verify server used --server-port instead of default or port in cache.xml
-      assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-      final ServerState status = this.launcher.status();
-      final String portString = status.getPort();
-      int port = Integer.valueOf(portString);
-      assertEquals("Port should be " + this.serverPort + " instead of " + port, this.serverPort,
-          port);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithServerPortOverridesPortInCacheXml() throws Exception {
+    givenCacheXmlFileWithServerPort(unusedServerPort);
+
+    ServerLauncher launcher = startServer(
+        addJvmArgument("-D" + GEMFIRE_PREFIX + CACHE_XML_FILE + "=" + getCacheXmlFilePath())
+            .withServerPort(nonDefaultServerPort));
+
+    // server should use --server-port instead of port in cache.xml
+    assertThatServerPortIsInUse(nonDefaultServerPort);
+    assertThatServerPortIsFree(unusedServerPort);
+    assertThat(Integer.valueOf(launcher.status().getPort())).isEqualTo(nonDefaultServerPort);
   }
 
-  @Category(FlakyTest.class) // GEODE-1135: random ports, BindException, fork JVM
   @Test
-  public void testStartWithDefaultPortInUseFails() throws Throwable {
-    String expectedString = "java.net.BindException";
-    AtomicBoolean outputContainedExpectedString = new AtomicBoolean();
-
-    // make serverPort in use
-    this.socket = SocketCreatorFactory
-        .createNonDefaultInstance(false, false, null, null, System.getProperties())
-        .createServerSocket(this.serverPort, 50, null, -1);
-    assertFalse(AvailablePort.isPortAvailable(this.serverPort, AvailablePort.SOCKET));
-
-    // launch server
-    final List<String> jvmArguments = getJvmArguments();
-    jvmArguments.add(
-        "-D" + AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY + "=" + this.serverPort);
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).inputListener(createExpectedListener("sysout",
-            getUniqueName() + "#sysout", expectedString, outputContainedExpectedString))
-        .build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).inputListener(createExpectedListener("syserr",
-            getUniqueName() + "#syserr", expectedString, outputContainedExpectedString))
-        .build().start();
-
-    // wait for server to start up
-    final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      int code = this.process.waitFor();
-      assertEquals("Expected exit code 1 but was " + code, 1, code);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // check the status
-      final ServerState serverState = dirLauncher.status();
-      assertNotNull(serverState);
-      assertEquals(Status.NOT_RESPONDING, serverState.getStatus());
-
-      // creation of log file seems to be random -- look into why sometime
-      final String logFileName = getUniqueName() + ".log";
-      assertFalse("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // if the following fails, then the SHORTER_TIMEOUT might be too short for slow machines
-    // or this test needs to use MainLauncher in ProcessWrapper
-
-    // validate that output contained BindException
-    this.errorCollector.checkThat(outputContainedExpectedString.get(), is(equalTo(true)));
-
-    // just in case the launcher started...
-    ServerState status = null;
-    try {
-      status = dirLauncher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
-
-    try {
-      assertEquals(getExpectedStopStatusForNotRunning(), status.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithServerPortOverridesDefaultWithCacheXml() throws Exception {
+    givenCacheXmlFile();
+
+    ServerLauncher launcher = startServer(
+        addJvmArgument("-D" + GEMFIRE_PREFIX + CACHE_XML_FILE + "=" + getCacheXmlFilePath())
+            .withServerPort(nonDefaultServerPort));
+
+    // verify server used --server-port instead of default
+    assertThatServerPortIsInUse(nonDefaultServerPort);
+    assertThatServerPortIsFree(defaultServerPort);
+    assertThat(Integer.valueOf(launcher.status().getPort())).isEqualTo(nonDefaultServerPort);
   }
 
   @Test
-  @Ignore("Need to rewrite this without using dunit.Host")
-  public void testStartWithExistingPidFileFails()
-      throws Throwable {}/*
-                          * this.temporaryFolder.getRoot() = new File(getUniqueName());
-                          * this.temporaryFolder.getRoot().mkdir();
-                          * assertTrue(this.temporaryFolder.getRoot().isDirectory() &&
-                          * this.temporaryFolder.getRoot().canWrite());
-                          * 
-                          * // create existing pid file this.pidFile = new
-                          * File(this.temporaryFolder.getRoot(),
-                          * ProcessType.SERVER.getPidFileName()); final int realPid =
-                          * Host.getHost(0).getVM(3).invoke(() -> ProcessUtils.identifyPid());
-                          * assertFalse("Remote pid shouldn't be the same as local pid " + realPid,
-                          * realPid == ProcessUtils.identifyPid()); writePid(this.pidFile, realPid);
-                          * 
-                          * // build and start the server final List<String> jvmArguments =
-                          * getJvmArguments();
-                          * 
-                          * final List<String> command = new ArrayList<String>(); command.add(new
-                          * File(new File(System.getProperty("java.home"), "bin"),
-                          * "java").getCanonicalPath()); for (String jvmArgument : jvmArguments) {
-                          * command.add(jvmArgument); } command.add("-cp");
-                          * command.add(System.getProperty("java.class.path"));
-                          * command.add(ServerLauncher.class.getName());
-                          * command.add(ServerLauncher.Command.START.getName());
-                          * command.add(getUniqueName()); command.add("--disable-default-server");
-                          * command.add("--redirect-output");
-                          * 
-                          * this.process = new
-                          * ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start(
-                          * ); this.processOutReader = new
-                          * ProcessStreamReader.Builder(this.process).inputStream(this.process.
-                          * getInputStream()).build().start(); this.processErrReader = new
-                          * ProcessStreamReader.Builder(this.process).inputStream(this.process.
-                          * getErrorStream()).build().start();
-                          * 
-                          * // collect and throw the FIRST failure Throwable failure = null;
-                          * 
-                          * final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-                          * .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath())
-                          * .build(); try { waitForServerToStart(dirLauncher, 10*1000, false); }
-                          * catch (Throwable e) { logger.error(e); if (failure == null) { failure =
-                          * e; } }
-                          * 
-                          * try { // check the status final ServerState serverState =
-                          * dirLauncher.status(); assertNotNull(serverState);
-                          * assertIndexDetailsEquals(Status.NOT_RESPONDING,
-                          * serverState.getStatus());
-                          * 
-                          * final String logFileName = getUniqueName()+".log";
-                          * assertFalse("Log file should not exist: " + logFileName, new
-                          * File(this.temporaryFolder.getRoot(), logFileName).exists());
-                          * 
-                          * } catch (Throwable e) { logger.error(e); if (failure == null) { failure
-                          * = e; } }
-                          * 
-                          * // just in case the launcher started... ServerState status = null; try {
-                          * status = dirLauncher.stop(); } catch (Throwable t) { // ignore }
-                          * 
-                          * try { final Status theStatus = status.getStatus(); assertFalse(theStatus
-                          * == Status.STARTING); assertFalse(theStatus == Status.ONLINE); } catch
-                          * (Throwable e) { logger.error(e); if (failure == null) { failure = e; } }
-                          * 
-                          * if (failure != null) { throw failure; } } //
-                          * testStartWithExistingPidFileFails
-                          */
-
-  @Category(FlakyTest.class) // GEODE-957: random ports, BindException, fork JVM
+  public void startWithDefaultPortInUseFailsWithBindException() throws Exception {
+    givenServerPortInUse(defaultServerPort);
+
+    startServerShouldFail();
+
+    assertThatServerThrew(BindException.class);
+  }
+
   @Test
-  public void testStatusUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for server to start
-    int pid = 0;
-    ServerLauncher pidLauncher = null;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
-
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      // validate the status
-      final ServerState actualStatus = pidLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath(),
-          actualStatus.getWorkingDirectory());
-      assertEquals(jvmArguments, actualStatus.getJvmArguments());
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath() + File.separator
-          + getUniqueName() + ".log", actualStatus.getLogFile());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      if (pidLauncher == null) {
-        assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      } else {
-        assertEquals(Status.STOPPED, pidLauncher.stop().getStatus());
-      }
-      waitForPidToStop(pid);
-      waitForFileToDelete(this.pidFile);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void statusForDisableDefaultServerHasEmptyPort() throws Exception {
+    givenRunningServer(withDisableDefaultServer());
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(serverState.getPort()).isEmpty();
   }
 
   @Test
-  public void testStatusUsingWorkingDirectory() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for server to start
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      assertNotNull(this.launcher);
-      assertFalse(this.launcher.isRunning());
-
-      // validate the status
-      final ServerState actualStatus = this.launcher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath(),
-          actualStatus.getWorkingDirectory());
-      assertEquals(jvmArguments, actualStatus.getJvmArguments());
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath() + File.separator
-          + getUniqueName() + ".log", actualStatus.getLogFile());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void statusWithPidReturnsOnlineWithDetails() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState = new Builder().setPid(getServerPid()).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(ONLINE);
+    assertThat(serverState.getPid().intValue()).isEqualTo(getServerPid());
+    assertThat(serverState.getUptime()).isGreaterThan(0);
+    assertThat(serverState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
+    assertThat(serverState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(serverState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(serverState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(serverState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(serverState.getLogFile()).isEqualTo(getLogFile().getCanonicalPath());
+    assertThat(serverState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(serverState.getMemberName()).isEqualTo(getUniqueName());
   }
 
   @Test
-  public void testStatusWithEmptyPidFile() throws Exception {
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-    assertTrue(this.pidFile + " already exists", this.pidFile.createNewFile());
-
-    final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    final ServerState actualStatus = dirLauncher.status();
-    assertThat(actualStatus, is(notNullValue()));
-    assertThat(actualStatus.getStatus(), is(equalTo(Status.NOT_RESPONDING)));
-    assertThat(actualStatus.getPid(), is(nullValue()));
-    assertThat(actualStatus.getUptime().intValue(), is(equalTo(0)));
-    assertThat(actualStatus.getWorkingDirectory(),
-        is(equalTo(this.temporaryFolder.getRoot().getCanonicalPath())));
-    assertThat(actualStatus.getClasspath(), is(nullValue()));
-    assertThat(actualStatus.getGemFireVersion(), is(equalTo(GemFireVersion.getGemFireVersion())));
-    assertThat(actualStatus.getJavaVersion(), is(nullValue()));
-    assertThat(actualStatus.getLogFile(), is(nullValue()));
-    assertThat(actualStatus.getHost(), is(nullValue()));
-    assertThat(actualStatus.getMemberName(), is(nullValue()));
+  public void statusWithWorkingDirectoryReturnsOnlineWithDetails() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(ONLINE);
+    assertThat(serverState.getPid().intValue()).isEqualTo(readPidFile());
+    assertThat(serverState.getUptime()).isGreaterThan(0);
+    assertThat(serverState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
+    assertThat(serverState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(serverState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(serverState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(serverState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(serverState.getLogFile()).isEqualTo(getLogFile().getCanonicalPath());
+    assertThat(serverState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(serverState.getMemberName()).isEqualTo(getUniqueName());
   }
 
   @Test
-  public void testStatusWithNoPidFile() throws Exception {
-    final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    ServerState serverState = dirLauncher.status();
-    assertEquals(Status.NOT_RESPONDING, serverState.getStatus());
+  public void statusWithEmptyPidFileThrowsIllegalArgumentException() throws Exception {
+    givenEmptyPidFile();
+
+    ServerLauncher launcher = new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build();
+
+    assertThatThrownBy(() -> launcher.status()).isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid pid 'null' found in");
   }
 
   @Test
-  public void testStatusWithStalePidFile() throws Exception {
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-    final int pid = 0;
-    assertFalse(ProcessUtils.isProcessAlive(pid));
-    writePid(this.pidFile, pid);
-
-    final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-        .setWorkingDirectory(temporaryFolder.getRoot().getCanonicalPath()).build();
-    final ServerState actualStatus = dirLauncher.status();
-    assertThat(actualStatus, is(notNullValue()));
-    assertThat(actualStatus.getStatus(), is(equalTo(Status.NOT_RESPONDING)));
-    assertThat(actualStatus.getPid(), is(nullValue()));
-    assertThat(actualStatus.getUptime().intValue(), is(equalTo(0)));
-    assertThat(actualStatus.getWorkingDirectory(),
-        is(equalTo(this.temporaryFolder.getRoot().getCanonicalPath())));
-    assertThat(actualStatus.getClasspath(), is(nullValue()));
-    assertThat(actualStatus.getGemFireVersion(), is(equalTo(GemFireVersion.getGemFireVersion())));
-    assertThat(actualStatus.getJavaVersion(), is(nullValue()));
-    assertThat(actualStatus.getLogFile(), is(nullValue()));
-    assertThat(actualStatus.getHost(), is(nullValue()));
-    assertThat(actualStatus.getMemberName(), is(nullValue()));
+  public void statusWithEmptyWorkingDirectoryReturnsNotRespondingWithDetails() throws Exception {
+    givenEmptyWorkingDirectory();
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(NOT_RESPONDING);
+    assertThat(serverState.getPid()).isNull();
+    assertThat(serverState.getUptime().intValue()).isEqualTo(0);
+    assertThat(serverState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
+    assertThat(serverState.getClasspath()).isNull();
+    assertThat(serverState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(serverState.getJavaVersion()).isNull();
+    assertThat(serverState.getLogFile()).isNull();
+    assertThat(serverState.getHost()).isNull();
+    assertThat(serverState.getMemberName()).isNull();
   }
 
   @Test
-  public void testStopUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(createLoggingListener("sysout", getUniqueName() + "#sysout")).build()
-            .start();
-    this.processErrReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(createLoggingListener("syserr", getUniqueName() + "#syserr")).build()
-            .start();
-
-    // wait for server to start
-    int pid = 0;
-    ServerLauncher pidLauncher = null;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
-
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      // validate the status
-      final ServerState status = pidLauncher.status();
-      assertNotNull(status);
-      assertEquals(Status.ONLINE, status.getStatus());
-      assertEquals(pid, status.getPid().intValue());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the server
-    try {
-      if (pidLauncher == null) {
-        assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      } else {
-        assertEquals(Status.STOPPED, pidLauncher.stop().getStatus());
-      }
-      waitForPidToStop(pid);
-      waitForFileToDelete(this.pidFile);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void statusWithStalePidFileReturnsNotResponding() throws Exception {
+    givenPidFile(fakePid);
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(serverState.getStatus()).isEqualTo(NOT_RESPONDING);
   }
 
   @Test
-  public void testStopUsingWorkingDirectory() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for server to start
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // stop the server
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-      assertFalse("PID file still exists!", this.pidFile.exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void stopWithPidReturnsStopped() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState = new Builder().setPid(getServerPid()).build().stop();
+
+    assertThat(serverState.getStatus()).isEqualTo(STOPPED);
   }
 
-  @Override
-  protected List<String> getJvmArguments() {
-    final List<String> jvmArguments = new ArrayList<String>();
-    jvmArguments.add(
-        "-D" + DistributionConfig.GEMFIRE_PREFIX + ConfigurationProperties.LOG_LEVEL + "=config");
-    jvmArguments
-        .add("-D" + DistributionConfig.GEMFIRE_PREFIX + ConfigurationProperties.MCAST_PORT + "=0");
-    return jvmArguments;
+  @Test
+  public void stopWithPidStopsServerProcess() throws Exception {
+    givenRunningServer();
+
+    new Builder().setPid(getServerPid()).build().stop();
+
+    assertStopOf(getServerProcess());
   }
 
-  /**
-   * Used only by
-   * {@link ServerLauncherRemoteIntegrationTest#testRunningServerOutlivesForkingProcess}
-   */
-  public static class ServerLauncherForkingProcess {
-
-    public static void main(final String... args) throws IOException, PidUnavailableException {
-      // -System.out.println("inside main");
-      File file = new File(System.getProperty("user.dir"),
-          ServerLauncherForkingProcess.class.getSimpleName().concat(".log"));
-      file.createNewFile();
-      LocalLogWriter logWriter = new LocalLogWriter(InternalLogWriter.ALL_LEVEL,
-          new PrintStream(new FileOutputStream(file, true)));
-      // LogWriter logWriter = new PureLogWriter(LogWriterImpl.ALL_LEVEL);
-      logWriter
-          .info(ServerLauncherForkingProcess.class.getSimpleName() + "#main PID is " + getPid());
-
-      try {
-        // launch ServerLauncher
-        final List<String> jvmArguments = null;// getJvmArguments();
-        assertTrue(jvmArguments.size() == 2);
-        final List<String> command = new ArrayList<String>();
-        command.add(
-            new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-        for (String jvmArgument : jvmArguments) {
-          command.add(jvmArgument);
-        }
-        command.add("-cp");
-        command.add(System.getProperty("java.class.path"));
-        command.add(ServerLauncher.class.getName());
-        command.add(ServerLauncher.Command.START.getName());
-        command.add(ServerLauncherForkingProcess.class.getSimpleName() + "_server");
-        command.add("--disable-default-server");
-        command.add("--redirect-output");
-
-        logWriter
-            .info(ServerLauncherForkingProcess.class.getSimpleName() + "#main command: " + command);
-        logWriter.info(ServerLauncherForkingProcess.class.getSimpleName() + "#main starting...");
-
-        // -System.out.println("launching " + command);
-
-        @SuppressWarnings("unused")
-        Process forkedProcess = new ProcessBuilder(command).start();
-
-        // processOutReader = new ProcessStreamReader(forkedProcess.getInputStream()).start();
-        // processErrReader = new ProcessStreamReader(forkedProcess.getErrorStream()).start();
-
-        // logWriter.info(ServerLauncherForkingProcess.class.getSimpleName() + "#main waiting for
-        // Server to start...");
-        //
-        // File workingDir = new File(System.getProperty("user.dir"));
-        // System.out.println("waiting for server to start in " + workingDir);
-        // final ServerLauncher dirLauncher = new ServerLauncher.Builder()
-        // .setWorkingDirectory(workingDir.getCanonicalPath())
-        // .build();
-        // waitForServerToStart(dirLauncher, true);
-
-        logWriter.info(ServerLauncherForkingProcess.class.getSimpleName() + "#main exiting...");
-
-        // -System.out.println("exiting");
-        ExitCode.NORMAL.doSystemExit();
-      } catch (Throwable t) {
-        logWriter.info(ServerLauncherForkingProcess.class.getSimpleName() + "#main error: " + t, t);
-        System.exit(-1);
-      }
-    }
+  @Test
+  public void stopWithPidDeletesPidFile() throws Exception {
+    givenRunningServer();
+
+    new Builder().setPid(getServerPid()).build().stop();
+
+    assertDeletionOf(getPidFile());
+  }
+
+  @Test
+  public void stopWithWorkingDirectoryReturnsStopped() throws Exception {
+    givenRunningServer();
+
+    ServerState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertThat(serverState.getStatus()).isEqualTo(STOPPED);
+  }
+
+  @Test
+  public void stopWithWorkingDirectoryStopsServerProcess() throws Exception {
+    givenRunningServer();
+
+    new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertStopOf(getServerProcess());
+  }
+
+  @Test
+  public void stopWithWorkingDirectoryDeletesPidFile() throws Exception {
+    givenRunningServer();
+
+    new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
+
+    assertDeletionOf(getPidFile());
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTestCase.java
new file mode 100644
index 0000000..a66b772
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteIntegrationTestCase.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static org.apache.geode.distributed.internal.DistributionConfig.GEMFIRE_PREFIX;
+import static org.apache.geode.internal.cache.AbstractCacheServer.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY;
+import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.BindException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.After;
+import org.junit.Before;
+
+import org.apache.geode.distributed.AbstractLauncher.Status;
+import org.apache.geode.internal.process.ProcessStreamReader;
+import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
+
+/**
+ * Abstract base class for integration tests of {@link ServerLauncher} as an application main in a
+ * forked JVM.
+ *
+ * @since GemFire 8.0
+ */
+public abstract class ServerLauncherRemoteIntegrationTestCase
+    extends ServerLauncherIntegrationTestCase implements UsesServerCommand {
+
+  private final AtomicBoolean threwBindException = new AtomicBoolean();
+
+  private volatile Process process;
+  private volatile ProcessStreamReader processOutReader;
+  private volatile ProcessStreamReader processErrReader;
+
+  private ServerCommand serverCommand;
+
+  @Before
+  public void setUpServerLauncherRemoteIntegrationTestCase() throws Exception {
+    serverCommand = new ServerCommand(this);
+  }
+
+  @After
+  public void tearDownServerLauncherRemoteIntegrationTestCase() throws Exception {
+    if (process != null) {
+      process.destroy();
+      process = null;
+    }
+    if (processOutReader != null && processOutReader.isRunning()) {
+      processOutReader.stop();
+    }
+    if (processErrReader != null && processErrReader.isRunning()) {
+      processErrReader.stop();
+    }
+  }
+
+  @Override
+  public boolean getDisableDefaultServer() {
+    return false;
+  }
+
+  @Override
+  public List<String> getJvmArguments() {
+    List<String> jvmArguments = new ArrayList<>();
+    jvmArguments.add("-D" + GEMFIRE_PREFIX + LOG_LEVEL + "=config");
+    jvmArguments.add("-D" + GEMFIRE_PREFIX + MCAST_PORT + "=0");
+    jvmArguments
+        .add("-D" + TEST_OVERRIDE_DEFAULT_PORT_PROPERTY + "=" + String.valueOf(defaultServerPort));
+    return jvmArguments;
+  }
+
+  @Override
+  public String getName() {
+    return getUniqueName();
+  }
+
+  protected void assertThatServerThrew(final Class<? extends Throwable> throwableClass) {
+    assertThat(threwBindException.get()).isTrue();
+  }
+
+  protected void assertStopOf(final Process process) {
+    await().until(() -> assertThat(process.isAlive()).isFalse());
+  }
+
+  protected void assertThatPidIsAlive(final int pid) {
+    assertThat(pid).isGreaterThan(0);
+    assertThat(isProcessAlive(pid)).isTrue();
+  }
+
+  protected ServerLauncher givenRunningServer() {
+    return givenRunningServer(serverCommand);
+  }
+
+  protected ServerLauncher givenRunningServer(final ServerCommand command) {
+    return awaitStart(command);
+  }
+
+  protected Process getServerProcess() {
+    return process;
+  }
+
+  @Override
+  protected ServerLauncher startServer() {
+    return startServer(serverCommand);
+  }
+
+  protected ServerLauncher startServer(final ServerCommand command) {
+    return awaitStart(command);
+  }
+
+  protected ServerLauncher startServer(final ServerCommand command,
+      final ProcessStreamReader.InputListener outListener,
+      final ProcessStreamReader.InputListener errListener) throws Exception {
+    executeCommandWithReaders(command.create(), outListener, errListener);
+    ServerLauncher launcher = awaitStart(getWorkingDirectory());
+    assertThat(process.isAlive()).isTrue();
+    return launcher;
+  }
+
+  protected void startServerShouldFail() throws IOException, InterruptedException {
+    startServerShouldFail(serverCommand);
+  }
+
+  protected void startServerShouldFail(final ServerCommand command)
+      throws IOException, InterruptedException {
+    startServerShouldFail(command, createBindExceptionListener("sysout", threwBindException),
+        createBindExceptionListener("syserr", threwBindException));
+  }
+
+  protected ServerCommand addJvmArgument(final String arg) {
+    return serverCommand.addJvmArgument(arg);
+  }
+
+  protected ServerCommand withDisableDefaultServer() {
+    return withDisableDefaultServer(true);
+  }
+
+  protected ServerCommand withDisableDefaultServer(final boolean value) {
+    return serverCommand.disableDefaultServer(value);
+  }
+
+  protected ServerCommand withForce() {
+    return withForce(true);
+  }
+
+  protected ServerCommand withForce(final boolean value) {
+    return serverCommand.force(value);
+  }
+
+  protected ServerCommand withServerPort(final int port) {
+    return serverCommand.withServerPort(port);
+  }
+
+  private ServerLauncher awaitStart(final File workingDirectory) {
+    try {
+      launcher = new ServerLauncher.Builder()
+          .setWorkingDirectory(workingDirectory.getCanonicalPath()).build();
+      awaitStart(launcher);
+      assertThat(process.isAlive()).isTrue();
+      return launcher;
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private ServerLauncher awaitStart(final ServerCommand command) {
+    try {
+      executeCommandWithReaders(command);
+      ServerLauncher launcher = awaitStart(getWorkingDirectory());
+      assertThat(process.isAlive()).isTrue();
+      return launcher;
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  @Override
+  protected ServerLauncher awaitStart(final ServerLauncher launcher) {
+    await().until(() -> assertThat(launcher.status().getStatus()).isEqualTo(Status.ONLINE));
+    assertThat(process.isAlive()).isTrue();
+    return launcher;
+  }
+
+  private InputListener createBindExceptionListener(final String name,
+      final AtomicBoolean threwBindException) {
+    return createExpectedListener(name, BindException.class.getName(), threwBindException);
+  }
+
+  private void executeCommandWithReaders(final List<String> command) throws IOException {
+    process = new ProcessBuilder(command).directory(getWorkingDirectory()).start();
+    processOutReader = new ProcessStreamReader.Builder(process)
+        .inputStream(process.getInputStream()).build().start();
+    processErrReader = new ProcessStreamReader.Builder(process)
+        .inputStream(process.getErrorStream()).build().start();
+  }
+
+  private void executeCommandWithReaders(final List<String> command,
+      final InputListener outListener, final InputListener errListener) throws IOException {
+    process = new ProcessBuilder(command).directory(getWorkingDirectory()).start();
+    processOutReader = new ProcessStreamReader.Builder(process)
+        .inputStream(process.getInputStream()).inputListener(outListener).build().start();
+    processErrReader = new ProcessStreamReader.Builder(process)
+        .inputStream(process.getErrorStream()).inputListener(errListener).build().start();
+  }
+
+  private void executeCommandWithReaders(final ServerCommand command) throws IOException {
+    executeCommandWithReaders(command.create());
+  }
+
+  private void startServerShouldFail(final ServerCommand command, final InputListener outListener,
+      final InputListener errListener) throws IOException, InterruptedException {
+    executeCommandWithReaders(command.create(), outListener, errListener);
+    process.waitFor(2, MINUTES);
+    assertThat(process.isAlive()).isFalse();
+    assertThat(process.exitValue()).isEqualTo(1);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteWithCustomLoggingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteWithCustomLoggingIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteWithCustomLoggingIntegrationTest.java
index fa3564b..99112db 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteWithCustomLoggingIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/ServerLauncherRemoteWithCustomLoggingIntegrationTest.java
@@ -14,24 +14,23 @@
  */
 package org.apache.geode.distributed;
 
-import static org.apache.geode.internal.logging.log4j.custom.CustomConfiguration.*;
-import static org.assertj.core.api.Assertions.*;
-import static org.junit.Assert.*;
+import static org.apache.geode.internal.logging.log4j.custom.CustomConfiguration.CONFIG_LAYOUT_PREFIX;
+import static org.apache.geode.internal.logging.log4j.custom.CustomConfiguration.createConfigFileIn;
+import static org.apache.logging.log4j.core.config.ConfigurationFactory.CONFIGURATION_FILE_PROPERTY;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
+import java.io.IOException;
+import java.io.UncheckedIOException;
 
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.contrib.java.lang.system.SystemOutRule;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
+import org.apache.geode.distributed.ServerLauncher.Command;
+import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
 import org.apache.geode.test.junit.categories.IntegrationTest;
 
 /**
@@ -39,89 +38,45 @@ import org.apache.geode.test.junit.categories.IntegrationTest;
  */
 @Category(IntegrationTest.class)
 public class ServerLauncherRemoteWithCustomLoggingIntegrationTest
-    extends AbstractServerLauncherRemoteIntegrationTestCase {
+    extends ServerLauncherRemoteIntegrationTestCase {
 
-  private File customConfigFile;
+  private File customLoggingConfigFile;
 
   @Rule
   public SystemOutRule systemOutRule = new SystemOutRule().enableLog();
 
   @Before
-  public void setUpLocatorLauncherRemoteWithCustomLoggingIntegrationTest() throws Exception {
-    this.customConfigFile = createConfigFileIn(this.temporaryFolder.getRoot());
+  public void setUpServerLauncherRemoteWithCustomLoggingIntegrationTest() throws Exception {
+    this.customLoggingConfigFile = createConfigFileIn(getWorkingDirectory());
   }
 
   @Test
-  public void testStartUsesCustomLoggingConfiguration() throws Throwable {
-    // build and start the server
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-D" + ConfigurationFactory.CONFIGURATION_FILE_PROPERTY + "="
-        + this.customConfigFile.getCanonicalPath());
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(ServerLauncher.class.getName());
-    command.add(ServerLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--disable-default-server");
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(new File(this.workingDirectory)).start();
-    this.processOutReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(new ToSystemOut()).build().start();
-    this.processErrReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(new ToSystemOut()).build().start();
-
-    int pid = 0;
-    this.launcher = new ServerLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForServerToStart();
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.SERVER.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // check the status
-      final ServerLauncher.ServerState serverState = this.launcher.status();
-      assertNotNull(serverState);
-      assertEquals(AbstractLauncher.Status.ONLINE, serverState.getStatus());
-
-      assertThat(systemOutRule.getLog())
-          .contains("log4j.configurationFile = " + this.customConfigFile.getCanonicalPath());
-      assertThat(systemOutRule.getLog()).contains(CONFIG_LAYOUT_PREFIX);
+  public void startWithCustomLoggingConfiguration() throws Exception {
+    startServer(
+        new ServerCommand(this).addJvmArgument(customLoggingConfigArgument())
+            .disableDefaultServer(true).withCommand(Command.START),
+        new ToSystemOut(), new ToSystemOut());
+
+    assertThat(systemOutRule.getLog())
+        .contains("log4j.configurationFile = " + getCustomLoggingConfigFilePath());
+    assertThat(systemOutRule.getLog()).contains(CONFIG_LAYOUT_PREFIX);
+  }
 
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  private String customLoggingConfigArgument() {
+    return "-D" + CONFIGURATION_FILE_PROPERTY + "=" + getCustomLoggingConfigFilePath();
+  }
 
-    // stop the server
+  private String getCustomLoggingConfigFilePath() {
     try {
-      assertEquals(AbstractLauncher.Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
+      return customLoggingConfigFile.getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
     }
   }
 
-  private static class ToSystemOut implements ProcessStreamReader.InputListener {
+  private static class ToSystemOut implements InputListener {
     @Override
-    public void notifyInputLine(String line) {
+    public void notifyInputLine(final String line) {
       System.out.println(line);
     }
   }


[05/23] geode git commit: GEODE-3328: refactor ConnectCommand

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSSLTest.java
----------------------------------------------------------------------
diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSSLTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSSLTest.java
new file mode 100644
index 0000000..7c4fb44
--- /dev/null
+++ b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSSLTest.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_CIPHERS;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_ENABLED;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_KEYSTORE_TYPE;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_PROTOCOLS;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_TRUSTSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_CIPHERS;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_ENABLED;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_KEYSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_KEYSTORE_TYPE;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_PROTOCOLS;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_TRUSTSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_CIPHERS;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_ENABLED;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_KEYSTORE_TYPE;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_PROTOCOLS;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_TRUSTSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_CIPHERS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_ENABLED_COMPONENTS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_TYPE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_TYPE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import java.util.Properties;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.security.SecurableCommunicationChannels;
+import org.apache.geode.test.dunit.IgnoredException;
+import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.DistributedTest;
+
+@Category(DistributedTest.class)
+public class ConnectCommandWithSSLTest {
+
+  private static File jks;
+
+  static {
+    try {
+      jks = new File(ConnectCommandWithSSLTest.class.getClassLoader()
+          .getResource("ssl/trusted.keystore").toURI());
+    } catch (URISyntaxException e) {
+      e.printStackTrace();
+    }
+  }
+
+  private static Properties sslProperties = new Properties() {
+    {
+      setProperty(SSL_ENABLED_COMPONENTS, SecurableCommunicationChannels.ALL);
+      setProperty(SSL_KEYSTORE, jks.getAbsolutePath());
+      setProperty(SSL_KEYSTORE_PASSWORD, "password");
+      setProperty(SSL_KEYSTORE_TYPE, "JKS");
+      setProperty(SSL_TRUSTSTORE, jks.getAbsolutePath());
+      setProperty(SSL_TRUSTSTORE_PASSWORD, "password");
+      setProperty(SSL_TRUSTSTORE_TYPE, "JKS");
+      setProperty(SSL_CIPHERS, "any");
+      setProperty(SSL_PROTOCOLS, "any");
+    }
+  };
+
+  private static Properties jmxSslProperties = new Properties() {
+    {
+      setProperty(JMX_MANAGER_SSL_ENABLED, "true");
+      setProperty(JMX_MANAGER_SSL_KEYSTORE, jks.getAbsolutePath());
+      setProperty(JMX_MANAGER_SSL_KEYSTORE_PASSWORD, "password");
+      setProperty(JMX_MANAGER_SSL_KEYSTORE_TYPE, "JKS");
+      setProperty(JMX_MANAGER_SSL_TRUSTSTORE, jks.getAbsolutePath());
+      setProperty(JMX_MANAGER_SSL_TRUSTSTORE_PASSWORD, "password");
+      setProperty(JMX_MANAGER_SSL_CIPHERS, "any");
+      setProperty(JMX_MANAGER_SSL_PROTOCOLS, "any");
+    }
+  };
+
+  private static Properties clusterSslProperties = new Properties() {
+    {
+      setProperty(CLUSTER_SSL_ENABLED, "true");
+      setProperty(CLUSTER_SSL_KEYSTORE, jks.getAbsolutePath());
+      setProperty(CLUSTER_SSL_KEYSTORE_PASSWORD, "password");
+      setProperty(CLUSTER_SSL_KEYSTORE_TYPE, "JKS");
+      setProperty(CLUSTER_SSL_TRUSTSTORE, jks.getAbsolutePath());
+      setProperty(CLUSTER_SSL_TRUSTSTORE_PASSWORD, "password");
+      setProperty(CLUSTER_SSL_CIPHERS, "any");
+      setProperty(CLUSTER_SSL_PROTOCOLS, "any");
+    }
+  };
+
+  private static Properties httpSslProperties = new Properties() {
+    {
+      setProperty(HTTP_SERVICE_SSL_ENABLED, "true");
+      setProperty(HTTP_SERVICE_SSL_KEYSTORE, jks.getAbsolutePath());
+      setProperty(HTTP_SERVICE_SSL_KEYSTORE_PASSWORD, "password");
+      setProperty(HTTP_SERVICE_SSL_KEYSTORE_TYPE, "JKS");
+      setProperty(HTTP_SERVICE_SSL_TRUSTSTORE, jks.getAbsolutePath());
+      setProperty(HTTP_SERVICE_SSL_TRUSTSTORE_PASSWORD, "password");
+      setProperty(HTTP_SERVICE_SSL_CIPHERS, "any");
+      setProperty(HTTP_SERVICE_SSL_PROTOCOLS, "any");
+    }
+  };
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public LocatorServerStartupRule lsRule = new LocatorServerStartupRule();
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+  private static MemberVM locator;
+  private OutputStream out = null;
+  private File sslConfigFile = null;
+
+  @Before
+  public void before() throws Exception {
+    locator = lsRule.startLocatorVM(0, sslProperties);
+    HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
+    IgnoredException.addIgnoredException("javax.net.ssl.SSLException: Unrecognized SSL message");
+    sslConfigFile = temporaryFolder.newFile("ssl.properties");
+    out = new FileOutputStream(sslConfigFile);
+  }
+
+  @Rule
+  public GfshShellConnectionRule gfsh = new GfshShellConnectionRule();
+
+  @Test
+  public void connectWithNoSSL() throws Exception {
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator);
+    assertThat(gfsh.isConnected()).isFalse();
+    // should fail at connecting to locator stage
+    assertThat(gfsh.getGfshOutput()).doesNotContain("Connecting to Manager at");
+    assertThat(gfsh.getGfshOutput())
+        .contains("trying to connect a non-SSL-enabled client to an SSL-enabled locator");
+
+    gfsh.connect(locator.getJmxPort(), GfshShellConnectionRule.PortType.jmxManger);
+    assertThat(gfsh.isConnected()).isFalse();
+    assertThat(gfsh.getGfshOutput()).contains("non-JRMP server at remote endpoint");
+
+    gfsh.connect(locator.getHttpPort(), GfshShellConnectionRule.PortType.http);
+    assertThat(gfsh.isConnected()).isFalse();
+    assertThat(gfsh.getGfshOutput()).contains("Unexpected end of file from server");
+  }
+
+  @Test
+  public void connectWithSSL() throws Exception {
+    sslProperties.store(out, null);
+
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+    gfsh.disconnect();
+
+    gfsh.connect(locator.getJmxPort(), GfshShellConnectionRule.PortType.jmxManger,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+    gfsh.disconnect();
+
+    gfsh.connect(locator.getHttpPort(), GfshShellConnectionRule.PortType.http,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+  }
+
+  @Test
+  public void connectWithJmxSSL() throws Exception {
+    jmxSslProperties.store(out, null);
+    // can't connect locator
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isFalse();
+    assertThat(gfsh.getGfshOutput()).doesNotContain("Connecting to Manager at");
+    assertThat(gfsh.getGfshOutput())
+        .contains("trying to connect a non-SSL-enabled client to an SSL-enabled locator");
+
+    // can connect to jmx
+    gfsh.connect(locator.getJmxPort(), GfshShellConnectionRule.PortType.jmxManger,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+    gfsh.disconnect();
+
+    // cannot conect to http
+    gfsh.connect(locator.getHttpPort(), GfshShellConnectionRule.PortType.http,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isFalse();
+  }
+
+  @Test
+  /*
+   * apparently cluster-ssl-* configurations are copied to jmx-ssl-* and http-server-ssl-*, so
+   * connection to other channels will succeed as well. see DistributionConfigImpl around line 986:
+   * if (!isConnected) { copySSLPropsToServerSSLProps(); copySSLPropsToJMXSSLProps();
+   * copyClusterSSLPropsToGatewaySSLProps(); copySSLPropsToHTTPSSLProps(); }
+   */
+  public void connectWithClusterSSL() throws Exception {
+    clusterSslProperties.store(out, null);
+    // can connect to locator and jmx
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+    gfsh.disconnect();
+
+    // can connect to jmx
+    gfsh.connect(locator.getJmxPort(), GfshShellConnectionRule.PortType.jmxManger,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+    gfsh.disconnect();
+
+    // can conect to http
+    gfsh.connect(locator.getHttpPort(), GfshShellConnectionRule.PortType.http,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+  }
+
+  @Test
+  public void connectWithHttpSSL() throws Exception {
+    httpSslProperties.store(out, null);
+    // can connect to locator and jmx
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isFalse();
+
+    // can connect to jmx
+    gfsh.connect(locator.getJmxPort(), GfshShellConnectionRule.PortType.jmxManger,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isFalse();
+
+    // cannot conect to http
+    gfsh.connect(locator.getHttpPort(), GfshShellConnectionRule.PortType.http,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+  }
+
+  @Test
+  public void connectWithClusterAndJmxSSL() throws Exception {
+    Properties combined = new Properties();
+    combined.putAll(jmxSslProperties);
+    combined.putAll(clusterSslProperties);
+    combined.store(out, null);
+
+    // can connect to both locator and jmx
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+  }
+
+
+  @Test
+  public void connectWithSSLAndThenWithNoSSL() throws Exception {
+    sslProperties.store(out, null);
+
+    // can connect to both locator and jmx
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator,
+        "security-properties-file", sslConfigFile.getAbsolutePath());
+    assertThat(gfsh.isConnected()).isTrue();
+    gfsh.disconnect();
+
+    // reconnect again with no SSL should fail
+    gfsh.connect(locator.getPort(), GfshShellConnectionRule.PortType.locator);
+    assertThat(gfsh.isConnected()).isFalse();
+    // it should fail at connecting to locator, not connecting to manager
+    assertThat(gfsh.getGfshOutput()).doesNotContain("Connecting to Manager at");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSecurityTest.java
----------------------------------------------------------------------
diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSecurityTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSecurityTest.java
new file mode 100644
index 0000000..838924a
--- /dev/null
+++ b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectCommandWithSecurityTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.geode.management.internal.cli.commands;
+
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.security.SimpleTestSecurityManager;
+import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
+import org.apache.geode.test.dunit.rules.LocatorStarterRule;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class ConnectCommandWithSecurityTest {
+
+  @ClassRule
+  public static LocatorStarterRule locator =
+      new LocatorStarterRule().withSecurityManager(SimpleTestSecurityManager.class).withAutoStart();
+
+  @Rule
+  public GfshShellConnectionRule gfsh = new GfshShellConnectionRule();
+
+  @Test
+  public void connectToLocator() throws Exception {
+    gfsh.secureConnectAndVerify(locator.getPort(), GfshShellConnectionRule.PortType.locator, "test",
+        "test");
+  }
+
+  @Test
+  public void connectOverJmx() throws Exception {
+    gfsh.secureConnectAndVerify(locator.getJmxPort(), GfshShellConnectionRule.PortType.jmxManger,
+        "test", "test");
+  }
+
+  @Test
+  public void connectOverHttp() throws Exception {
+    gfsh.secureConnectAndVerify(locator.getHttpPort(), GfshShellConnectionRule.PortType.http,
+        "test", "test");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectToLocatorSSLOverHttpTest.java
----------------------------------------------------------------------
diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectToLocatorSSLOverHttpTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectToLocatorSSLOverHttpTest.java
deleted file mode 100644
index e5b8d25..0000000
--- a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ConnectToLocatorSSLOverHttpTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package org.apache.geode.management.internal.cli.commands;
-
-import javax.net.ssl.HttpsURLConnection;
-
-import org.apache.geode.management.ConnectToLocatorSSLDUnitTest;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
-
-public class ConnectToLocatorSSLOverHttpTest extends ConnectToLocatorSSLDUnitTest {
-
-  protected void connect() throws Exception {
-    final int httpPort = locator.getHttpPort();
-    final String securityPropsFilePath = securityPropsFile.getCanonicalPath();
-    Host.getHost(0).getVM(1).invoke(() -> {
-      // Our SSL certificate used for tests does not match the hostname "localhost"
-      HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
-
-      GfshShellConnectionRule gfshConnector = new GfshShellConnectionRule();
-      gfshConnector.connectAndVerify(httpPort, GfshShellConnectionRule.PortType.http,
-          CliStrings.CONNECT__SECURITY_PROPERTIES, securityPropsFilePath,
-          CliStrings.CONNECT__USE_SSL, "true");
-      gfshConnector.executeAndVerifyCommand("list members");
-      gfshConnector.close();
-    });
-  }
-}
-


[20/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/FileProcessController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/FileProcessController.java b/geode-core/src/main/java/org/apache/geode/internal/process/FileProcessController.java
index c8ec49d..062cfb6 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/FileProcessController.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/FileProcessController.java
@@ -14,13 +14,10 @@
  */
 package org.apache.geode.internal.process;
 
-import org.apache.commons.lang.StringUtils;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.i18n.LocalizedStrings;
-import org.apache.geode.internal.logging.LogService;
-import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
-import org.apache.geode.lang.AttachAPINotFoundException;
-import org.apache.logging.log4j.Logger;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.Validate.isTrue;
+import static org.apache.commons.lang.Validate.notNull;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -30,70 +27,72 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.apache.geode.internal.i18n.LocalizedStrings;
+import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
+import org.apache.geode.lang.AttachAPINotFoundException;
+
 /**
  * Controls a {@link ControllableProcess} using files to communicate between processes.
  * 
  * @since GemFire 8.0
  */
-public class FileProcessController implements ProcessController {
-  private static final Logger logger = LogService.getLogger();
+class FileProcessController implements ProcessController {
 
-  public static final String STATUS_TIMEOUT_PROPERTY =
-      DistributionConfig.GEMFIRE_PREFIX + "FileProcessController.STATUS_TIMEOUT";
+  static final long DEFAULT_STATUS_TIMEOUT_MILLIS = 60 * 1000;
 
   private final long statusTimeoutMillis;
-  private final FileControllerParameters arguments;
+  private final FileControllerParameters parameters;
   private final int pid;
 
   /**
    * Constructs an instance for controlling a local process.
    * 
-   * @param arguments details about the controllable process
+   * @param parameters details about the controllable process
    * @param pid process id identifying the process to control
    * 
    * @throws IllegalArgumentException if pid is not a positive integer
    */
-  public FileProcessController(final FileControllerParameters arguments, final int pid) {
-    this(arguments, pid, Long.getLong(STATUS_TIMEOUT_PROPERTY, 60 * 1000), TimeUnit.MILLISECONDS);
+  FileProcessController(final FileControllerParameters parameters, final int pid) {
+    this(parameters, pid, DEFAULT_STATUS_TIMEOUT_MILLIS, MILLISECONDS);
   }
 
   /**
    * Constructs an instance for controlling a local process.
    * 
-   * @param arguments details about the controllable process
+   * @param parameters details about the controllable process
    * @param pid process id identifying the process to control
    * @param timeout the timeout that operations must complete within
    * @param units the units of the timeout
    * 
    * @throws IllegalArgumentException if pid is not a positive integer
    */
-  public FileProcessController(final FileControllerParameters arguments, final int pid,
+  FileProcessController(final FileControllerParameters parameters, final int pid,
       final long timeout, final TimeUnit units) {
-    if (pid < 1) {
-      throw new IllegalArgumentException("Invalid pid '" + pid + "' specified");
-    }
+    notNull(parameters, "Invalid parameters '" + parameters + "' specified");
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+    isTrue(timeout >= 0, "Invalid timeout '" + timeout + "' specified");
+    notNull(units, "Invalid units '" + units + "' specified");
+
     this.pid = pid;
-    this.arguments = arguments;
+    this.parameters = parameters;
     this.statusTimeoutMillis = units.toMillis(timeout);
   }
 
   @Override
   public int getProcessId() {
-    return this.pid;
+    return pid;
   }
 
   @Override
   public String status()
       throws UnableToControlProcessException, IOException, InterruptedException, TimeoutException {
-    return status(this.arguments.getWorkingDirectory(),
-        this.arguments.getProcessType().getStatusRequestFileName(),
-        this.arguments.getProcessType().getStatusFileName());
+    return status(parameters.getDirectory(), parameters.getProcessType().getStatusRequestFileName(),
+        parameters.getProcessType().getStatusFileName());
   }
 
   @Override
   public void stop() throws UnableToControlProcessException, IOException {
-    stop(this.arguments.getWorkingDirectory(),
-        this.arguments.getProcessType().getStopRequestFileName());
+    stop(parameters.getDirectory(), parameters.getProcessType().getStopRequestFileName());
   }
 
   @Override
@@ -102,8 +101,12 @@ public class FileProcessController implements ProcessController {
         LocalizedStrings.Launcher_ATTACH_API_NOT_FOUND_ERROR_MESSAGE.toLocalizedString());
   }
 
+  long getStatusTimeoutMillis() {
+    return statusTimeoutMillis;
+  }
+
   private void stop(final File workingDir, final String stopRequestFileName) throws IOException {
-    final File stopRequestFile = new File(workingDir, stopRequestFileName);
+    File stopRequestFile = new File(workingDir, stopRequestFileName);
     if (!stopRequestFile.exists()) {
       stopRequestFile.createNewFile();
     }
@@ -112,56 +115,40 @@ public class FileProcessController implements ProcessController {
   private String status(final File workingDir, final String statusRequestFileName,
       final String statusFileName) throws IOException, InterruptedException, TimeoutException {
     // monitor for statusFile
-    final File statusFile = new File(workingDir, statusFileName);
-    final AtomicReference<String> statusRef = new AtomicReference<>();
-
-    final ControlRequestHandler statusHandler = new ControlRequestHandler() {
-      @Override
-      public void handleRequest() throws IOException {
-        // read the statusFile
-        final BufferedReader reader = new BufferedReader(new FileReader(statusFile));
-        final StringBuilder lines = new StringBuilder();
-        try {
-          String line = null;
-          while ((line = reader.readLine()) != null) {
-            lines.append(line);
-          }
-        } finally {
-          statusRef.set(lines.toString());
-          reader.close();
-        }
+    File statusFile = new File(workingDir, statusFileName);
+    AtomicReference<String> statusRef = new AtomicReference<>();
+
+    ControlRequestHandler statusHandler = () -> {
+      // read the statusFile
+      StringBuilder lines = new StringBuilder();
+      try (BufferedReader reader = new BufferedReader(new FileReader(statusFile))) {
+        reader.lines().forEach(lines::append);
+      } finally {
+        statusRef.set(lines.toString());
       }
     };
 
-    final ControlFileWatchdog statusFileWatchdog =
+    ControlFileWatchdog statusFileWatchdog =
         new ControlFileWatchdog(workingDir, statusFileName, statusHandler, true);
     statusFileWatchdog.start();
 
-    final File statusRequestFile = new File(workingDir, statusRequestFileName);
+    File statusRequestFile = new File(workingDir, statusRequestFileName);
     if (!statusRequestFile.exists()) {
       statusRequestFile.createNewFile();
     }
 
     // if timeout invoke stop and then throw TimeoutException
-    final long start = System.currentTimeMillis();
+    long start = System.currentTimeMillis();
     while (statusFileWatchdog.isAlive()) {
       Thread.sleep(10);
-      if (System.currentTimeMillis() >= start + this.statusTimeoutMillis) {
-        final TimeoutException te =
-            new TimeoutException("Timed out waiting for process to create " + statusFile);
-        try {
-          statusFileWatchdog.stop();
-        } catch (InterruptedException e) {
-          logger.info("Interrupted while stopping status file watchdog.", e);
-        } catch (RuntimeException e) {
-          logger.info("Unexpected failure while stopping status file watchdog.", e);
-        }
-        throw te;
+      if (System.currentTimeMillis() >= start + statusTimeoutMillis) {
+        statusFileWatchdog.stop();
+        throw new TimeoutException("Timed out waiting for process to create " + statusFile);
       }
     }
 
-    final String lines = statusRef.get();
-    if (StringUtils.isBlank(lines)) {
+    String lines = statusRef.get();
+    if (isBlank(lines)) {
       throw new IllegalStateException("Failed to read status file");
     }
     return lines;

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java b/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java
deleted file mode 100755
index fbea19e..0000000
--- a/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessController.java
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
-import java.util.Properties;
-import java.util.Set;
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanException;
-import javax.management.MBeanServerConnection;
-import javax.management.ObjectName;
-import javax.management.Query;
-import javax.management.QueryExp;
-import javax.management.ReflectionException;
-import javax.management.remote.JMXConnector;
-import javax.management.remote.JMXConnectorFactory;
-import javax.management.remote.JMXServiceURL;
-
-import org.apache.geode.internal.util.IOUtils;
-import com.sun.tools.attach.AgentInitializationException;
-import com.sun.tools.attach.AgentLoadException;
-import com.sun.tools.attach.AttachNotSupportedException;
-import com.sun.tools.attach.VirtualMachine;
-
-/**
- * Attaches to a local process to control it via JMX.
- * 
- * @since GemFire 7.0
- * @deprecated as of 8.0 please use {@link ControllableProcess} instead
- */
-public class LocalProcessController {
-
-  /** Property name for the JMX local connector address (from sun.management.Agent) */
-  private static final String LOCAL_CONNECTOR_ADDRESS_PROP =
-      "com.sun.management.jmxremote.localConnectorAddress";
-
-  private final int pid;
-
-  protected JMXConnector jmxc;
-  protected MBeanServerConnection server;
-
-  /**
-   * Constructs an instance for controlling a local process.
-   * 
-   * @param pid process id identifying the process to attach to
-   * 
-   * @throws IllegalArgumentException if pid is not a positive integer
-   */
-  public LocalProcessController(final int pid) {
-    if (pid < 1) {
-      throw new IllegalArgumentException("Invalid pid '" + pid + "' specified");
-    }
-    this.pid = pid;
-  }
-
-  /**
-   * Constructs an instance for controlling a local process.
-   * 
-   * @param pidFile file containing the pid of the process to attach to
-   * 
-   * @throws FileNotFoundException if the specified file name is not found within the directory
-   * @throws IOException if unable to read from the specified file
-   * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer
-   * @throws NumberFormatException if the pid file does not contain a parsable integer
-   */
-  public LocalProcessController(final File pidFile) throws IOException {
-    this(readPid(pidFile));
-  }
-
-  /**
-   * Constructs an instance for controlling a local process.
-   * 
-   * @param directory directory containing a file of name pidFileName
-   * @param pidFilename name of the file containing the pid of the process to attach to
-   * 
-   * @throws FileNotFoundException if the specified file name is not found within the directory
-   * @throws IOException if an I/O error occurs
-   * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer
-   * @throws IllegalStateException if dir is not an existing directory
-   * @throws NumberFormatException if the pid file does not contain a parsable integer
-   */
-  public LocalProcessController(final File directory, final String pidFilename) throws IOException {
-    this(readPid(directory, pidFilename));
-  }
-
-  /**
-   * Connects to the process and tells it to shut down.
-   * 
-   * @param namePattern the name pattern of the MBean to use for stopping
-   * @param pidAttribute the name of the MBean attribute with the process id to compare against
-   * @param stopMethod the name of the MBean operation to invoke
-   * @param attributes the names of the MBean attributes to compare with expected values
-   * @param values the expected values of the specified MBean attributes
-   *
-   * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector
-   *         in the process
-   * @throws IOException if a communication problem occurred when talking to the MBean server
-   * @throws MBeanInvocationFailedException if failed to invoke stop on the MBean for any reason
-   * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails
-   */
-  public void stop(final ObjectName namePattern, final String pidAttribute, final String stopMethod,
-      final String[] attributes, final Object[] values) throws ConnectionFailedException,
-      IOException, MBeanInvocationFailedException, PidUnavailableException {
-    invokeOperationOnTargetMBean(namePattern, pidAttribute, stopMethod, attributes, values);
-  }
-
-  /**
-   * Connects to the process and acquires its status.
-   * 
-   * @param namePattern the name pattern of the MBean to use for stopping
-   * @param pidAttribute the name of the MBean attribute with the process id to compare against
-   * @param statusMethod the name of the MBean operation to invoke
-   * @param attributes the names of the MBean attributes to compare with expected values
-   * @param values the expected values of the specified MBean attributes
-   * 
-   * @return string describing the status of the process
-   *
-   * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector
-   *         in the process
-   * @throws IOException if a communication problem occurred when talking to the MBean server
-   * @throws MBeanInvocationFailedException if failed to invoke stop on the MBean for any reason
-   * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails
-   */
-  public String status(final ObjectName namePattern, final String pidAttribute,
-      final String statusMethod, final String[] attributes, final Object[] values)
-      throws ConnectionFailedException, IOException, MBeanInvocationFailedException,
-      PidUnavailableException {
-    return invokeOperationOnTargetMBean(namePattern, pidAttribute, statusMethod, attributes, values)
-        .toString();
-  }
-
-  /**
-   * Connects to the process and use its MBean to stop it.
-   * 
-   * @param namePattern the name pattern of the MBean to use for stopping
-   * @param pidAttribute the name of the MBean attribute with the process id to compare against
-   * @param methodName the name of the MBean operation to invoke
-   * @param attributes the names of the MBean attributes to compare with expected values
-   * @param values the expected values of the specified MBean attributes
-   *
-   * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector
-   *         in the process
-   * @throws IOException if a communication problem occurred when talking to the MBean server
-   * @throws MBeanInvocationFailedException if failed to invoke stop on the MBean for any reason
-   * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails
-   */
-  private Object invokeOperationOnTargetMBean(final ObjectName namePattern,
-      final String pidAttribute, final String methodName, final String[] attributes,
-      final Object[] values) throws ConnectionFailedException, IOException,
-      MBeanInvocationFailedException, PidUnavailableException {
-    ObjectName objectName = namePattern;
-    connect();
-    try {
-      final QueryExp constraint = buildQueryExp(pidAttribute, attributes, values);
-      final Set<ObjectName> mbeanNames = this.server.queryNames(namePattern, constraint);
-
-      if (mbeanNames.isEmpty()) {
-        throw new MBeanInvocationFailedException("Failed to find mbean matching '" + namePattern
-            + "' with attribute '" + pidAttribute + "' of value '" + this.pid + "'");
-      }
-      if (mbeanNames.size() > 1) {
-        throw new MBeanInvocationFailedException("Found more than one mbean matching '"
-            + namePattern + "' with attribute '" + pidAttribute + "' of value '" + this.pid + "'");
-      }
-
-      objectName = mbeanNames.iterator().next();
-      return invoke(objectName, methodName);
-    } catch (InstanceNotFoundException e) {
-      throw new MBeanInvocationFailedException(
-          "Failed to invoke " + methodName + " on " + objectName, e);
-    } catch (MBeanException e) {
-      throw new MBeanInvocationFailedException(
-          "Failed to invoke " + methodName + " on " + objectName, e);
-    } catch (ReflectionException e) {
-      throw new MBeanInvocationFailedException(
-          "Failed to invoke " + methodName + " on " + objectName, e);
-    } finally {
-      disconnect();
-    }
-  }
-
-  /**
-   * Returns the process id (pid) of the process.
-   * 
-   * @return the process id (pid) of the process
-   */
-  public int getProcessId() {
-    return this.pid;
-  }
-
-  /**
-   * Connects to the JMX agent in the local process.
-   * 
-   * @throws ConnectionFailedException if there was a failure to connect to the local JMX connector
-   *         in the process
-   * @throws IOException if the JDK management agent cannot be found and loaded
-   */
-  void connect() throws ConnectionFailedException, IOException {
-    try {
-      final JMXServiceURL jmxUrl = getJMXServiceURL();
-      this.jmxc = JMXConnectorFactory.connect(jmxUrl);
-      this.server = this.jmxc.getMBeanServerConnection();
-    } catch (AttachNotSupportedException e) {
-      throw new ConnectionFailedException("Failed to connect to process '" + this.pid + "'", e);
-    }
-  }
-
-  /**
-   * Disconnects from the JMX agent in the local process.
-   */
-  void disconnect() {
-    this.server = null;
-    if (this.jmxc != null) {
-      try {
-        this.jmxc.close();
-      } catch (IOException e) {
-        // ignore
-      }
-    }
-    this.jmxc = null;
-  }
-
-  /**
-   * Ensures that the other process identifies itself by the same pid used by this stopper to
-   * connect to that process. NOT USED EXCEPT IN TEST.
-   * 
-   * @return true if the pid matches
-   * 
-   * @throws IllegalStateException if the other process identifies itself by a different pid
-   * @throws IOException if a communication problem occurred when accessing the
-   *         MBeanServerConnection
-   * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails
-   */
-  boolean checkPidMatches() throws IllegalStateException, IOException, PidUnavailableException {
-    final RuntimeMXBean proxy = ManagementFactory.newPlatformMXBeanProxy(this.server,
-        ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
-    final int remotePid = ProcessUtils.identifyPid(proxy.getName());
-    if (remotePid != this.pid) {
-      throw new IllegalStateException(
-          "Process has different pid '" + remotePid + "' than expected pid '" + this.pid + "'");
-    } else {
-      return true;
-    }
-  }
-
-  /**
-   * Uses the Attach API to connect to the local process and ensures that it has loaded the JMX
-   * management agent. The JMXServiceURL identifying the local connector address for the JMX agent
-   * in the process is returned.
-   * 
-   * @return the address of the JMX API connector server for connecting to the local process
-   * 
-   * @throws AttachNotSupportedException if unable to use the Attach API to connect to the process
-   * @throws IOException if the JDK management agent cannot be found and loaded
-   */
-  private JMXServiceURL getJMXServiceURL() throws AttachNotSupportedException, IOException {
-    String connectorAddress = null;
-    final VirtualMachine vm = VirtualMachine.attach(String.valueOf(this.pid));
-    try {
-      Properties agentProps = vm.getAgentProperties();
-      connectorAddress = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
-
-      if (connectorAddress == null) {
-        // need to load the management-agent and get the address
-
-        final String javaHome = vm.getSystemProperties().getProperty("java.home");
-
-        // assume java.home is JDK and look in JRE for agent
-        String managementAgentPath = javaHome + File.separator + "jre" + File.separator + "lib"
-            + File.separator + "management-agent.jar";
-        File managementAgent = new File(managementAgentPath);
-        if (!managementAgent.exists()) {
-          // assume java.home is JRE and look in lib for agent
-          managementAgentPath =
-              javaHome + File.separator + "lib" + File.separator + "management-agent.jar";
-          managementAgent = new File(managementAgentPath);
-          if (!managementAgent.exists()) {
-            throw new IOException("JDK management agent not found");
-          }
-        }
-
-        // attempt to load the management agent
-        managementAgentPath = managementAgent.getCanonicalPath();
-        try {
-          vm.loadAgent(managementAgentPath, "com.sun.management.jmxremote");
-        } catch (AgentLoadException e) {
-          IOException ioe = new IOException(e.getMessage());
-          ioe.initCause(e);
-          throw ioe;
-        } catch (AgentInitializationException e) {
-          IOException ioe = new IOException(e.getMessage());
-          ioe.initCause(e);
-          throw ioe;
-        }
-
-        // get the connector address
-        agentProps = vm.getAgentProperties();
-        connectorAddress = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
-      }
-    } finally {
-      vm.detach();
-    }
-
-    if (connectorAddress == null) {
-      // should never reach here
-      throw new IOException("Failed to find address to attach to process");
-    }
-
-    return new JMXServiceURL(connectorAddress);
-  }
-
-  /**
-   * Builds the QueryExp used to identify the target MBean.
-   * 
-   * @param pidAttribute the name of the MBean attribute with the process id to compare against
-   * @param attributes the names of additional MBean attributes to compare with expected values
-   * @param values the expected values of the specified MBean attributes
-   *
-   * @return the main QueryExp for matching the target MBean
-   */
-  private QueryExp buildQueryExp(final String pidAttribute, final String[] attributes,
-      final Object[] values) {
-    final QueryExp optionalAttributes = buildOptionalQueryExp(attributes, values);
-    QueryExp constraint;
-    if (optionalAttributes != null) {
-      constraint =
-          Query.and(optionalAttributes, Query.eq(Query.attr(pidAttribute), Query.value(this.pid)));
-    } else {
-      constraint = Query.eq(Query.attr(pidAttribute), Query.value(this.pid));
-    }
-    return constraint;
-  }
-
-  /**
-   * Builds an optional QueryExp to aid in matching the correct MBean using additional attributes
-   * with the specified values. Returns null if no attributes and values were specified during
-   * construction.
-   * 
-   * @param attributes the names of additional MBean attributes to compare with expected values
-   * @param values the expected values of the specified MBean attributes
-   *
-   * @return optional QueryExp to aid in matching the correct MBean
-   */
-  private QueryExp buildOptionalQueryExp(final String[] attributes, final Object[] values) {
-    QueryExp queryExp = null;
-    for (int i = 0; i < attributes.length; i++) {
-      if (values[i] instanceof Boolean) {
-        if (queryExp == null) {
-          queryExp = Query.eq(Query.attr(attributes[i]), Query.value(((Boolean) values[i])));
-        } else {
-          queryExp = Query.and(queryExp,
-              Query.eq(Query.attr(attributes[i]), Query.value(((Boolean) values[i]))));
-        }
-      } else if (values[i] instanceof Number) {
-        if (queryExp == null) {
-          queryExp = Query.eq(Query.attr(attributes[i]), Query.value((Number) values[i]));
-        } else {
-          queryExp = Query.and(queryExp,
-              Query.eq(Query.attr(attributes[i]), Query.value((Number) values[i])));
-        }
-      } else if (values[i] instanceof String) {
-        if (queryExp == null) {
-          queryExp = Query.eq(Query.attr(attributes[i]), Query.value((String) values[i]));
-        } else {
-          queryExp = Query.and(queryExp,
-              Query.eq(Query.attr(attributes[i]), Query.value((String) values[i])));
-        }
-      }
-    }
-    return queryExp;
-  }
-
-  /**
-   * Invokes an operation on the specified MBean.
-   * 
-   * @param objectName identifies the MBean
-   * @param method the name of the operation method invoke
-   * 
-   * @return the result of invoking the operation on the MBean specified or null
-   * 
-   * @throws InstanceNotFoundException if the specified MBean is not registered in the MBean server
-   * @throws IOException if a communication problem occurred when talking to the MBean server
-   * @throws MBeanException if the MBean operation throws an exception
-   * @throws ReflectionException if the MBean does not have the specified operation
-   */
-  private Object invoke(final ObjectName objectName, final String method)
-      throws InstanceNotFoundException, IOException, MBeanException, ReflectionException {
-    return this.server.invoke(objectName, method, new Object[] {}, new String[] {});
-  }
-
-  /**
-   * Reads in the pid from the specified file.
-   * 
-   * @param pidFile the file containing the pid of the process to stop
-   * 
-   * @return the process id (pid) contained within the pidFile
-   * 
-   * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer
-   * @throws IOException if unable to read from the specified file
-   * @throws NumberFormatException if the pid file does not contain a parsable integer
-   */
-  private static int readPid(final File pidFile) throws IOException {
-    BufferedReader fileReader = null;
-    String pidValue = null;
-
-    try {
-      fileReader = new BufferedReader(new FileReader(pidFile));
-      pidValue = fileReader.readLine();
-
-      final int pid = Integer.parseInt(pidValue);
-
-      if (pid < 1) {
-        throw new IllegalArgumentException("Invalid pid '" + pid + "' found in " + pidFile);
-      }
-
-      return pid;
-    } catch (NumberFormatException e) {
-      throw new IllegalArgumentException("Invalid pid '" + pidValue + "' found in " + pidFile);
-    } finally {
-      IOUtils.close(fileReader);
-    }
-  }
-
-  /**
-   * Reads in the pid from the named file contained within the specified directory.
-   * 
-   * @param directory directory containing a file of name pidFileName
-   * @param pidFilename name of the file containing the pid of the process to stop
-   * 
-   * @return the process id (pid) contained within the pidFile
-   * 
-   * @throws FileNotFoundException if the specified file name is not found within the directory
-   * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer
-   * @throws IllegalStateException if dir is not an existing directory
-   * @throws IOException if an I/O error occurs
-   * @throws NumberFormatException if the pid file does not contain a parsable integer
-   */
-  private static int readPid(final File directory, final String pidFilename) throws IOException {
-    if (!directory.isDirectory() && directory.exists()) {
-      throw new IllegalArgumentException(
-          "Argument '" + directory + "' must be an existing directory!");
-    }
-
-    final File[] files = directory.listFiles(new FilenameFilter() {
-      @Override
-      public boolean accept(File file, String filename) {
-        return filename.equals(pidFilename);
-      }
-    });
-
-    if (files.length == 0) {
-      throw new FileNotFoundException(
-          "Unable to find PID file '" + pidFilename + "' in directory " + directory);
-    }
-
-    return readPid(files[0]);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessLauncher.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessLauncher.java b/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessLauncher.java
index 04809c2..598a75e 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessLauncher.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/LocalProcessLauncher.java
@@ -14,16 +14,21 @@
  */
 package org.apache.geode.internal.process;
 
-import org.apache.geode.distributed.internal.DistributionConfig;
+import static org.apache.commons.lang.Validate.notNull;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
 
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 
+import org.apache.geode.distributed.internal.DistributionConfig;
+
 /**
  * Creates a pid file and writes the process id to the pid file.
- * <p/>
+ *
+ * <p>
  * Related articles and libraries:
+ *
  * <ul>
  * <li>http://barelyenough.org/blog/2005/03/java-daemon/
  * <li>http://stackoverflow.com/questions/534648/how-to-daemonize-a-java-program
@@ -31,12 +36,13 @@ import java.io.IOException;
  * <li>http://wrapper.tanukisoftware.com/
  * <li>http://weblogs.java.net/blog/kohsuke/archive/2009/01/writing_a_unix.html
  * <li>http://www.enderunix.org/docs/eng/daemon.php
+ * </ul>
  * 
  * @since GemFire 7.0
  */
-public class LocalProcessLauncher {
+class LocalProcessLauncher {
 
-  public static final String PROPERTY_IGNORE_IS_PID_ALIVE =
+  static final String PROPERTY_IGNORE_IS_PID_ALIVE =
       DistributionConfig.GEMFIRE_PREFIX + "test.LocalProcessLauncher.ignoreIsPidAlive";
 
   private final int pid;
@@ -55,9 +61,11 @@ public class LocalProcessLauncher {
    * 
    * @see java.lang.management.RuntimeMXBean
    */
-  public LocalProcessLauncher(final File pidFile, final boolean force)
+  LocalProcessLauncher(final File pidFile, final boolean force)
       throws FileAlreadyExistsException, IOException, PidUnavailableException {
-    this.pid = ProcessUtils.identifyPid();
+    notNull(pidFile, "Invalid pidFile '" + pidFile + "' specified");
+
+    this.pid = identifyPid();
     this.pidFile = pidFile;
     writePid(force);
   }
@@ -67,8 +75,8 @@ public class LocalProcessLauncher {
    * 
    * @return the process id (pid)
    */
-  public int getPid() {
-    return this.pid;
+  int getPid() {
+    return pid;
   }
 
   /**
@@ -76,15 +84,28 @@ public class LocalProcessLauncher {
    * 
    * @return the pid file
    */
-  public File getPidFile() {
-    return this.pidFile;
+  File getPidFile() {
+    return pidFile;
   }
 
   /**
    * Delete the pid file now. {@link java.io.File#deleteOnExit()} is set on the pid file.
+   *
    */
   void close() {
-    this.pidFile.delete();
+    pidFile.delete();
+  }
+
+  /**
+   * Delete the pid file now. {@link java.io.File#deleteOnExit()} is set on the pid file.
+   *
+   * @param deletePidFileOnClose if true then the pid file will be deleted now instead of during JVM
+   *        exit
+   */
+  void close(final boolean deletePidFileOnClose) {
+    if (deletePidFileOnClose) {
+      pidFile.delete();
+    }
   }
 
   /**
@@ -96,30 +117,44 @@ public class LocalProcessLauncher {
    * @throws IOException if unable to create or write to the file
    */
   private void writePid(final boolean force) throws FileAlreadyExistsException, IOException {
-    final boolean created = this.pidFile.createNewFile();
-    if (!created && !force) {
-      int otherPid = 0;
-      try {
-        otherPid = ProcessUtils.readPid(this.pidFile);
-      } catch (IOException e) {
-        // suppress
-      } catch (NumberFormatException e) {
-        // suppress
-      }
-      boolean ignorePidFile = false;
-      if (otherPid != 0 && !ignoreIsPidAlive()) {
-        ignorePidFile = !ProcessUtils.isProcessAlive(otherPid);
-      }
-      if (!ignorePidFile) {
-        throw new FileAlreadyExistsException("Pid file already exists: " + this.pidFile + " for "
-            + (otherPid > 0 ? "process " + otherPid : "unknown process"));
+    if (pidFile.exists()) {
+      if (!force) {
+        checkOtherPid(readOtherPid());
       }
+      pidFile.delete();
+    }
+
+    File tempPidFile = new File(pidFile.getParent(), pidFile.getName() + ".tmp");
+    tempPidFile.createNewFile();
+
+    try (FileWriter writer = new FileWriter(tempPidFile)) {
+      writer.write(String.valueOf(pid));
+      writer.flush();
     }
-    this.pidFile.deleteOnExit();
-    final FileWriter writer = new FileWriter(this.pidFile);
-    writer.write(String.valueOf(this.pid));
-    writer.flush();
-    writer.close();
+
+    tempPidFile.renameTo(pidFile);
+    pidFile.deleteOnExit();
+  }
+
+  private int readOtherPid() {
+    int otherPid = 0;
+    try {
+      otherPid = ProcessUtils.readPid(pidFile);
+    } catch (NumberFormatException | IOException ignore) {
+      // suppress
+    }
+    return otherPid;
+  }
+
+  private void checkOtherPid(final int otherPid) throws FileAlreadyExistsException {
+    if (ignoreIsPidAlive() || otherPid != 0 && isProcessAlive(otherPid)) {
+      throw new FileAlreadyExistsException("Pid file already exists: " + pidFile + " for "
+          + (otherPid > 0 ? "process " + otherPid : "unknown process"));
+    }
+  }
+
+  private boolean isProcessAlive(final int pid) {
+    return ignoreIsPidAlive() || ProcessUtils.isProcessAlive(pid);
   }
 
   private static boolean ignoreIsPidAlive() {

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/MBeanControllerParameters.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/MBeanControllerParameters.java b/geode-core/src/main/java/org/apache/geode/internal/process/MBeanControllerParameters.java
index 857c52d..2ea0fa4 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/MBeanControllerParameters.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/MBeanControllerParameters.java
@@ -25,15 +25,16 @@ import org.apache.geode.internal.process.ProcessController.Arguments;
  * @since GemFire 8.0
  */
 interface MBeanControllerParameters extends Arguments {
-  public ObjectName getNamePattern();
 
-  public String getPidAttribute();
+  ObjectName getNamePattern();
 
-  public String getStatusMethod();
+  String getPidAttribute();
 
-  public String getStopMethod();
+  String getStatusMethod();
 
-  public String[] getAttributes();
+  String getStopMethod();
 
-  public Object[] getValues();
+  String[] getAttributes();
+
+  Object[] getValues();
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/MBeanInvocationFailedException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/MBeanInvocationFailedException.java b/geode-core/src/main/java/org/apache/geode/internal/process/MBeanInvocationFailedException.java
index 724a4d7..d4ba3ec 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/MBeanInvocationFailedException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/MBeanInvocationFailedException.java
@@ -23,23 +23,23 @@ public class MBeanInvocationFailedException extends Exception {
   private static final long serialVersionUID = 7991096466859690801L;
 
   /**
-   * Creates a new <code>MBeanInvocationFailedException</code>.
+   * Creates a new {@code MBeanInvocationFailedException}.
    */
   public MBeanInvocationFailedException(final String message) {
     super(message);
   }
 
   /**
-   * Creates a new <code>MBeanInvocationFailedException</code> that was caused by a given exception
+   * Creates a new {@code MBeanInvocationFailedException} that was caused by a given exception
    */
-  public MBeanInvocationFailedException(final String message, final Throwable thr) {
-    super(message, thr);
+  public MBeanInvocationFailedException(final String message, final Throwable cause) {
+    super(message, cause);
   }
 
   /**
-   * Creates a new <code>MBeanInvocationFailedException</code> that was caused by a given exception
+   * Creates a new {@code MBeanInvocationFailedException} that was caused by a given exception
    */
-  public MBeanInvocationFailedException(final Throwable thr) {
-    super(thr.getMessage(), thr);
+  public MBeanInvocationFailedException(final Throwable cause) {
+    super(cause.getMessage(), cause);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/MBeanProcessController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/MBeanProcessController.java b/geode-core/src/main/java/org/apache/geode/internal/process/MBeanProcessController.java
index ea5946e..1a19719 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/MBeanProcessController.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/MBeanProcessController.java
@@ -14,10 +14,11 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.isTrue;
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.File;
 import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.lang.management.RuntimeMXBean;
 import java.util.Properties;
 import java.util.Set;
 
@@ -42,17 +43,20 @@ import com.sun.tools.attach.VirtualMachine;
  * 
  * @since GemFire 8.0
  */
-public class MBeanProcessController implements ProcessController {
+class MBeanProcessController implements ProcessController {
 
   /** Property name for the JMX local connector address (from sun.management.Agent) */
-  private static final String LOCAL_CONNECTOR_ADDRESS_PROP =
+  private static final String PROPERTY_LOCAL_CONNECTOR_ADDRESS =
       "com.sun.management.jmxremote.localConnectorAddress";
 
+  private static final Object[] PARAMS = {};
+  private static final String[] SIGNATURE = {};
+
   private final MBeanControllerParameters arguments;
   private final int pid;
 
-  protected JMXConnector jmxc;
-  protected MBeanServerConnection server;
+  private JMXConnector jmxc;
+  private MBeanServerConnection server;
 
   /**
    * Constructs an instance for controlling a local process.
@@ -61,36 +65,37 @@ public class MBeanProcessController implements ProcessController {
    * 
    * @throws IllegalArgumentException if pid is not a positive integer
    */
-  public MBeanProcessController(final MBeanControllerParameters arguments, final int pid) {
-    if (pid < 1) {
-      throw new IllegalArgumentException("Invalid pid '" + pid + "' specified");
-    }
+  MBeanProcessController(final MBeanControllerParameters arguments, final int pid) {
+    notNull(arguments, "Invalid arguments '" + arguments + "' specified");
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
     this.pid = pid;
     this.arguments = arguments;
   }
 
   @Override
   public int getProcessId() {
-    return this.pid;
+    return pid;
   }
 
   @Override
   public String status() throws UnableToControlProcessException, ConnectionFailedException,
       IOException, MBeanInvocationFailedException {
-    return status(this.arguments.getNamePattern(), this.arguments.getPidAttribute(),
-        this.arguments.getStatusMethod(), this.arguments.getAttributes(),
-        this.arguments.getValues());
+    return status(arguments.getNamePattern(), arguments.getPidAttribute(),
+        arguments.getStatusMethod(), arguments.getAttributes(), arguments.getValues());
   }
 
   @Override
   public void stop() throws UnableToControlProcessException, ConnectionFailedException, IOException,
       MBeanInvocationFailedException {
-    stop(this.arguments.getNamePattern(), this.arguments.getPidAttribute(),
-        this.arguments.getStopMethod(), this.arguments.getAttributes(), this.arguments.getValues());
+    stop(arguments.getNamePattern(), arguments.getPidAttribute(), arguments.getStopMethod(),
+        arguments.getAttributes(), arguments.getValues());
   }
 
   @Override
-  public void checkPidSupport() {}
+  public void checkPidSupport() {
+    // nothing
+  }
 
   /**
    * Connects to the process and tells it to shut down.
@@ -156,27 +161,21 @@ public class MBeanProcessController implements ProcessController {
     ObjectName objectName = namePattern;
     connect();
     try {
-      final QueryExp constraint = buildQueryExp(pidAttribute, attributes, values);
-      final Set<ObjectName> mbeanNames = this.server.queryNames(namePattern, constraint);
+      QueryExp constraint = buildQueryExp(pidAttribute, attributes, values);
+      Set<ObjectName> mbeanNames = server.queryNames(namePattern, constraint);
 
       if (mbeanNames.isEmpty()) {
         throw new MBeanInvocationFailedException("Failed to find mbean matching '" + namePattern
-            + "' with attribute '" + pidAttribute + "' of value '" + this.pid + "'");
+            + "' with attribute '" + pidAttribute + "' of value '" + pid + "'");
       }
       if (mbeanNames.size() > 1) {
         throw new MBeanInvocationFailedException("Found more than one mbean matching '"
-            + namePattern + "' with attribute '" + pidAttribute + "' of value '" + this.pid + "'");
+            + namePattern + "' with attribute '" + pidAttribute + "' of value '" + pid + "'");
       }
 
       objectName = mbeanNames.iterator().next();
       return invoke(objectName, methodName);
-    } catch (InstanceNotFoundException e) {
-      throw new MBeanInvocationFailedException(
-          "Failed to invoke " + methodName + " on " + objectName, e);
-    } catch (MBeanException e) {
-      throw new MBeanInvocationFailedException(
-          "Failed to invoke " + methodName + " on " + objectName, e);
-    } catch (ReflectionException e) {
+    } catch (InstanceNotFoundException | MBeanException | ReflectionException e) {
       throw new MBeanInvocationFailedException(
           "Failed to invoke " + methodName + " on " + objectName, e);
     } finally {
@@ -193,11 +192,11 @@ public class MBeanProcessController implements ProcessController {
    */
   private void connect() throws ConnectionFailedException, IOException {
     try {
-      final JMXServiceURL jmxUrl = getJMXServiceURL();
-      this.jmxc = JMXConnectorFactory.connect(jmxUrl);
-      this.server = this.jmxc.getMBeanServerConnection();
+      JMXServiceURL jmxUrl = getJMXServiceURL();
+      jmxc = JMXConnectorFactory.connect(jmxUrl);
+      server = jmxc.getMBeanServerConnection();
     } catch (AttachNotSupportedException e) {
-      throw new ConnectionFailedException("Failed to connect to process '" + this.pid + "'", e);
+      throw new ConnectionFailedException("Failed to connect to process '" + pid + "'", e);
     }
   }
 
@@ -205,38 +204,15 @@ public class MBeanProcessController implements ProcessController {
    * Disconnects from the JMX agent in the local process.
    */
   private void disconnect() {
-    this.server = null;
-    if (this.jmxc != null) {
+    server = null;
+    if (jmxc != null) {
       try {
-        this.jmxc.close();
-      } catch (IOException e) {
+        jmxc.close();
+      } catch (IOException ignored) {
         // ignore
       }
     }
-    this.jmxc = null;
-  }
-
-  /**
-   * Ensures that the other process identifies itself by the same pid used by this stopper to
-   * connect to that process. NOT USED EXCEPT IN TEST.
-   * 
-   * @return true if the pid matches
-   * 
-   * @throws IllegalStateException if the other process identifies itself by a different pid
-   * @throws IOException if a communication problem occurred when accessing the
-   *         MBeanServerConnection
-   * @throws PidUnavailableException if parsing the pid from the RuntimeMXBean name fails
-   */
-  boolean checkPidMatches() throws IllegalStateException, IOException, PidUnavailableException {
-    final RuntimeMXBean proxy = ManagementFactory.newPlatformMXBeanProxy(this.server,
-        ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
-    final int remotePid = ProcessUtils.identifyPid(proxy.getName());
-    if (remotePid != this.pid) {
-      throw new IllegalStateException(
-          "Process has different pid '" + remotePid + "' than expected pid '" + this.pid + "'");
-    } else {
-      return true;
-    }
+    jmxc = null;
   }
 
   /**
@@ -250,16 +226,16 @@ public class MBeanProcessController implements ProcessController {
    * @throws IOException if the JDK management agent cannot be found and loaded
    */
   private JMXServiceURL getJMXServiceURL() throws AttachNotSupportedException, IOException {
-    String connectorAddress = null;
-    final VirtualMachine vm = VirtualMachine.attach(String.valueOf(this.pid));
+    String connectorAddress;
+    VirtualMachine vm = VirtualMachine.attach(String.valueOf(pid));
     try {
       Properties agentProps = vm.getAgentProperties();
-      connectorAddress = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
+      connectorAddress = agentProps.getProperty(PROPERTY_LOCAL_CONNECTOR_ADDRESS);
 
       if (connectorAddress == null) {
         // need to load the management-agent and get the address
 
-        final String javaHome = vm.getSystemProperties().getProperty("java.home");
+        String javaHome = vm.getSystemProperties().getProperty("java.home");
 
         // assume java.home is JDK and look in JRE for agent
         String managementAgentPath = javaHome + File.separator + "jre" + File.separator + "lib"
@@ -279,19 +255,13 @@ public class MBeanProcessController implements ProcessController {
         managementAgentPath = managementAgent.getCanonicalPath();
         try {
           vm.loadAgent(managementAgentPath, "com.sun.management.jmxremote");
-        } catch (AgentLoadException e) {
-          IOException ioe = new IOException(e.getMessage());
-          ioe.initCause(e);
-          throw ioe;
-        } catch (AgentInitializationException e) {
-          IOException ioe = new IOException(e.getMessage());
-          ioe.initCause(e);
-          throw ioe;
+        } catch (AgentLoadException | AgentInitializationException e) {
+          throw new IOException(e);
         }
 
         // get the connector address
         agentProps = vm.getAgentProperties();
-        connectorAddress = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
+        connectorAddress = agentProps.getProperty(PROPERTY_LOCAL_CONNECTOR_ADDRESS);
       }
     } finally {
       vm.detach();
@@ -316,13 +286,13 @@ public class MBeanProcessController implements ProcessController {
    */
   private QueryExp buildQueryExp(final String pidAttribute, final String[] attributes,
       final Object[] values) {
-    final QueryExp optionalAttributes = buildOptionalQueryExp(attributes, values);
+    QueryExp optionalAttributes = buildOptionalQueryExp(attributes, values);
     QueryExp constraint;
     if (optionalAttributes != null) {
       constraint =
-          Query.and(optionalAttributes, Query.eq(Query.attr(pidAttribute), Query.value(this.pid)));
+          Query.and(optionalAttributes, Query.eq(Query.attr(pidAttribute), Query.value(pid)));
     } else {
-      constraint = Query.eq(Query.attr(pidAttribute), Query.value(this.pid));
+      constraint = Query.eq(Query.attr(pidAttribute), Query.value(pid));
     }
     return constraint;
   }
@@ -342,10 +312,10 @@ public class MBeanProcessController implements ProcessController {
     for (int i = 0; i < attributes.length; i++) {
       if (values[i] instanceof Boolean) {
         if (queryExp == null) {
-          queryExp = Query.eq(Query.attr(attributes[i]), Query.value(((Boolean) values[i])));
+          queryExp = Query.eq(Query.attr(attributes[i]), Query.value((Boolean) values[i]));
         } else {
           queryExp = Query.and(queryExp,
-              Query.eq(Query.attr(attributes[i]), Query.value(((Boolean) values[i]))));
+              Query.eq(Query.attr(attributes[i]), Query.value((Boolean) values[i])));
         }
       } else if (values[i] instanceof Number) {
         if (queryExp == null) {
@@ -381,6 +351,6 @@ public class MBeanProcessController implements ProcessController {
    */
   private Object invoke(final ObjectName objectName, final String method)
       throws InstanceNotFoundException, IOException, MBeanException, ReflectionException {
-    return this.server.invoke(objectName, method, new Object[] {}, new String[] {});
+    return server.invoke(objectName, method, PARAMS, SIGNATURE);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/NativeProcessUtils.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/NativeProcessUtils.java b/geode-core/src/main/java/org/apache/geode/internal/process/NativeProcessUtils.java
index 34cf81f..cea73de 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/NativeProcessUtils.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/NativeProcessUtils.java
@@ -14,6 +14,8 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.isTrue;
+
 import org.apache.geode.internal.process.ProcessUtils.InternalProcessUtils;
 import org.apache.geode.internal.shared.NativeCalls;
 
@@ -24,17 +26,19 @@ import org.apache.geode.internal.shared.NativeCalls;
  */
 class NativeProcessUtils implements InternalProcessUtils {
 
-  private final static NativeCalls nativeCalls = NativeCalls.getInstance();
-
-  NativeProcessUtils() {}
+  private static final NativeCalls nativeCalls = NativeCalls.getInstance();
 
   @Override
-  public boolean isProcessAlive(int pid) {
+  public boolean isProcessAlive(final int pid) {
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
     return nativeCalls.isProcessActive(pid);
   }
 
   @Override
-  public boolean killProcess(int pid) {
+  public boolean killProcess(final int pid) {
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
     return nativeCalls.killProcess(pid);
   }
 

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/NonBlockingProcessStreamReader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/NonBlockingProcessStreamReader.java b/geode-core/src/main/java/org/apache/geode/internal/process/NonBlockingProcessStreamReader.java
index d5c1116..9096fae 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/NonBlockingProcessStreamReader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/NonBlockingProcessStreamReader.java
@@ -30,7 +30,7 @@ import org.apache.geode.internal.util.StopWatch;
  * 
  * @since GemFire 8.2
  */
-public class NonBlockingProcessStreamReader extends ProcessStreamReader {
+class NonBlockingProcessStreamReader extends ProcessStreamReader {
   private static final Logger logger = LogService.getLogger();
 
   /**
@@ -39,61 +39,65 @@ public class NonBlockingProcessStreamReader extends ProcessStreamReader {
    */
   private final long continueReadingMillis;
 
-  protected NonBlockingProcessStreamReader(final Builder builder) {
+  private final StopWatch continueReading;
+
+  private StringBuilder stringBuilder;
+  private int character;
+  private boolean ready;
+
+  NonBlockingProcessStreamReader(final Builder builder) {
     super(builder);
-    continueReadingMillis = builder.continueReadingMillis;
+
+    this.continueReadingMillis = builder.continueReadingMillis;
+    this.continueReading = new StopWatch();
+    this.stringBuilder = new StringBuilder();
+    this.character = 0;
+    this.ready = false;
   }
 
   @Override
   public void run() {
-    final boolean isDebugEnabled = logger.isDebugEnabled();
-    if (isDebugEnabled) {
-      logger.debug("Running {}", this);
-    }
-    StopWatch continueReading = new StopWatch();
-    BufferedReader reader = null;
-    try {
-      reader = new BufferedReader(new InputStreamReader(inputStream));
-      StringBuilder sb = new StringBuilder();
-      boolean ready = false;
-      int ch = 0;
-      while (ch != -1) {
-        while ((ready = reader.ready()) && (ch = reader.read()) != -1) {
-          sb.append((char) ch);
-          if ((char) ch == '\n') {
-            this.inputListener.notifyInputLine(sb.toString());
-            sb = new StringBuilder();
-          }
-        }
-        if (!ready) {
-          if (!ProcessUtils.isProcessAlive(process)) {
-            if (!continueReading.isRunning()) {
-              continueReading.start();
-            } else if (continueReading.elapsedTimeMillis() > continueReadingMillis) {
-              return;
-            }
-          }
-          Thread.sleep(10);
+    try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
+      while (character != -1) {
+        readWhileReady(reader);
+        if (shouldTerminate()) {
+          break;
         }
       }
     } catch (IOException e) {
-      if (isDebugEnabled) {
+      if (logger.isDebugEnabled()) {
         logger.debug("Failure reading from buffered input stream: {}", e.getMessage(), e);
       }
     } catch (InterruptedException e) {
-      if (isDebugEnabled) {
+      if (logger.isDebugEnabled()) {
         logger.debug("Interrupted reading from buffered input stream: {}", e.getMessage(), e);
       }
-    } finally {
-      try {
-        reader.close();
-      } catch (IOException e) {
-        if (isDebugEnabled) {
-          logger.debug("Failure closing buffered input stream reader: {}", e.getMessage(), e);
-        }
+    }
+  }
+
+  private boolean shouldTerminate() throws InterruptedException {
+    if (!ProcessUtils.isProcessAlive(process)) {
+      if (!continueReading.isRunning()) {
+        continueReading.start();
+      } else if (continueReading.elapsedTimeMillis() > continueReadingMillis) {
+        return true;
       }
-      if (isDebugEnabled) {
-        logger.debug("Terminating {}", this);
+    }
+    Thread.sleep(10);
+    return false;
+  }
+
+  /**
+   * This is a hot reader while there are characters ready to read. As soon as there are no more
+   * characters to read, it returns and the loop invokes shouldTerminate which has a 10 millisecond
+   * sleep until there are more characters ready to read.
+   */
+  private void readWhileReady(BufferedReader reader) throws IOException {
+    while ((ready = reader.ready()) && (character = reader.read()) != -1) {
+      stringBuilder.append((char) character);
+      if ((char) character == '\n') {
+        this.inputListener.notifyInputLine(stringBuilder.toString());
+        stringBuilder = new StringBuilder();
       }
     }
   }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/PidFile.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/PidFile.java b/geode-core/src/main/java/org/apache/geode/internal/process/PidFile.java
index 291c202..0e7adf2 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/PidFile.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/PidFile.java
@@ -14,17 +14,15 @@
  */
 package org.apache.geode.internal.process;
 
+import static org.apache.commons.lang.Validate.isTrue;
+import static org.apache.commons.lang.Validate.notEmpty;
+import static org.apache.commons.lang.Validate.notNull;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
-import java.io.FilenameFilter;
 import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.apache.geode.internal.util.IOUtils;
-import org.apache.geode.internal.util.StopWatch;
 
 /**
  * File wrapper that adds support for reading process id (pid) from a pid file written to disk by
@@ -34,8 +32,6 @@ import org.apache.geode.internal.util.StopWatch;
  */
 public class PidFile {
 
-  private static final long SLEEP_INTERVAL_MILLIS = 10;
-
   private final File pidFile;
 
   /**
@@ -43,17 +39,13 @@ public class PidFile {
    * 
    * @param file the file containing the pid of the process
    * 
-   * @throws FileNotFoundException if the specified file name is not found within the directory
+   * @throws IllegalArgumentException if the specified file is null or does not exist
    */
-  public PidFile(final File file) throws FileNotFoundException {
-    if (!file.exists() || !file.isFile()) {
-      throw new FileNotFoundException("Unable to find PID file '" + file + "'");
-    }
-    this.pidFile = file;
-  }
+  public PidFile(final File file) {
+    notNull(file, "Invalid file '" + file + "' specified");
+    isTrue(file.exists(), "Nonexistent file '" + file + "' specified");
 
-  File getFile() {
-    return this.pidFile;
+    this.pidFile = file;
   }
 
   /**
@@ -62,19 +54,19 @@ public class PidFile {
    * @param directory directory containing a file of name pidFileName
    * @param filename name of the file containing the pid of the process to stop
    * 
-   * @throws FileNotFoundException if the specified file name is not found within the directory
-   * @throws IllegalStateException if dir is not an existing directory
+   * @throws FileNotFoundException if the specified filename is not found within the directory
+   * @throws IllegalArgumentException if directory is null, does not exist or is not a directory
    */
   public PidFile(final File directory, final String filename) throws FileNotFoundException {
-    if (!directory.isDirectory() && directory.exists()) {
-      throw new IllegalArgumentException(
-          "Argument '" + directory + "' must be an existing directory!");
-    }
+    notNull(directory, "Invalid directory '" + directory + "' specified");
+    notEmpty(filename, "Invalid filename '" + filename + "' specified");
+    isTrue(directory.isDirectory() && directory.exists(),
+        "Nonexistent directory '" + directory + "' specified");
 
-    final File file = new File(directory, filename);
+    File file = new File(directory, filename);
     if (!file.exists() || file.isDirectory()) {
       throw new FileNotFoundException(
-          "Unable to find PID file '" + filename + "' in directory " + directory);
+          "Unable to find PID file '" + filename + "' in directory '" + directory + "'");
     }
 
     this.pidFile = file;
@@ -89,81 +81,26 @@ public class PidFile {
    * @throws IOException if unable to read from the specified file
    */
   public int readPid() throws IOException {
-    BufferedReader fileReader = null;
     String pidValue = null;
-
-    try {
-      fileReader = new BufferedReader(new FileReader(this.pidFile));
+    try (BufferedReader fileReader = new BufferedReader(new FileReader(pidFile))) {
       pidValue = fileReader.readLine();
 
-      final int pid = Integer.parseInt(pidValue);
+      int pid = Integer.parseInt(pidValue);
 
       if (pid < 1) {
         throw new IllegalArgumentException(
-            "Invalid pid '" + pid + "' found in " + this.pidFile.getCanonicalPath());
+            "Invalid pid '" + pid + "' found in " + pidFile.getCanonicalPath());
       }
 
       return pid;
-    } catch (NumberFormatException e) {
+    } catch (NumberFormatException ignored) {
       throw new IllegalArgumentException(
-          "Invalid pid '" + pidValue + "' found in " + this.pidFile.getCanonicalPath());
-    } finally {
-      IOUtils.close(fileReader);
+          "Invalid pid '" + pidValue + "' found in " + pidFile.getCanonicalPath());
     }
   }
 
-  /**
-   * Reads in the pid from the specified file, retrying until the specified timeout.
-   * 
-   * @param timeout the maximum time to spend trying to read the pidFile
-   * @param unit the unit of timeout
-   * 
-   * @return the process id (pid) contained within the pidFile
-   * 
-   * @throws IllegalArgumentException if the pid in the pidFile is not a positive integer
-   * @throws IOException if unable to read from the specified file
-   * @throws InterruptedException if interrupted
-   * @throws TimeoutException if operation times out
-   */
-  public int readPid(final long timeout, final TimeUnit unit)
-      throws IOException, InterruptedException, TimeoutException {
-    IllegalArgumentException iae = null;
-    IOException ioe = null;
-    int pid = 0;
-
-    final long timeoutMillis = unit.toMillis(timeout);
-    final StopWatch stopWatch = new StopWatch(true);
-
-    while (pid <= 0) {
-      try {
-        pid = readPid();
-      } catch (IllegalArgumentException e) {
-        iae = e;
-      } catch (IOException e) {
-        ioe = e;
-      }
-      if (stopWatch.elapsedTimeMillis() > timeoutMillis) {
-        if (iae != null) {
-          throw new TimeoutException(iae.getMessage());
-        }
-        if (ioe != null) {
-          throw new TimeoutException(ioe.getMessage());
-        }
-      } else {
-        try {
-          Thread.sleep(SLEEP_INTERVAL_MILLIS);
-        } catch (InterruptedException e) {
-          Thread.currentThread().interrupt();
-          if (iae != null) {
-            throw new InterruptedException(iae.getMessage());
-          }
-          if (ioe != null) {
-            throw new InterruptedException(ioe.getMessage());
-          }
-          throw e;
-        }
-      }
-    }
-    return pid;
+  File getFile() {
+    return pidFile;
   }
+
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/PidUnavailableException.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/PidUnavailableException.java b/geode-core/src/main/java/org/apache/geode/internal/process/PidUnavailableException.java
index 6fa1c9f..934e65c 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/PidUnavailableException.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/PidUnavailableException.java
@@ -24,23 +24,23 @@ public class PidUnavailableException extends Exception {
   private static final long serialVersionUID = -1660269538268828059L;
 
   /**
-   * Creates a new <code>PidUnavailableException</code>.
+   * Creates a new {@code PidUnavailableException}.
    */
   public PidUnavailableException(final String message) {
     super(message);
   }
 
   /**
-   * Creates a new <code>PidUnavailableException</code> that was caused by a given exception
+   * Creates a new {@code PidUnavailableException} that was caused by a given exception
    */
-  public PidUnavailableException(final String message, final Throwable thr) {
-    super(message, thr);
+  public PidUnavailableException(final String message, final Throwable cause) {
+    super(message, cause);
   }
 
   /**
-   * Creates a new <code>PidUnavailableException</code> that was caused by a given exception
+   * Creates a new {@code PidUnavailableException} that was caused by a given exception
    */
-  public PidUnavailableException(final Throwable thr) {
-    super(thr.getMessage(), thr);
+  public PidUnavailableException(final Throwable cause) {
+    super(cause.getMessage(), cause);
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessController.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessController.java
index 2aa4732..2e5cb0c 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessController.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessController.java
@@ -27,19 +27,19 @@ public interface ProcessController {
   /**
    * Returns the status of a running GemFire {@link ControllableProcess}.
    */
-  public String status() throws UnableToControlProcessException, ConnectionFailedException,
-      IOException, MBeanInvocationFailedException, InterruptedException, TimeoutException;
+  String status() throws UnableToControlProcessException, ConnectionFailedException, IOException,
+      MBeanInvocationFailedException, InterruptedException, TimeoutException;
 
   /**
    * Stops a running GemFire {@link ControllableProcess}.
    */
-  public void stop() throws UnableToControlProcessException, ConnectionFailedException, IOException,
+  void stop() throws UnableToControlProcessException, ConnectionFailedException, IOException,
       MBeanInvocationFailedException;
 
   /**
    * Returns the PID of a running GemFire {@link ControllableProcess}.
    */
-  public int getProcessId();
+  int getProcessId();
 
   /**
    * Checks if {@link #status} and {@link #stop} are supported if only the PID is provided. Only the
@@ -48,14 +48,15 @@ public interface ProcessController {
    * 
    * @throws org.apache.geode.lang.AttachAPINotFoundException if the Attach API is not found
    */
-  public void checkPidSupport();
+  void checkPidSupport();
 
   /**
    * Defines the arguments that a client must provide to the ProcessController.
    */
-  static interface Arguments {
-    public int getProcessId();
+  interface Arguments {
 
-    public ProcessType getProcessType();
+    int getProcessId();
+
+    ProcessType getProcessType();
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerFactory.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerFactory.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerFactory.java
index 38fdcf8..ef276c3 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerFactory.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerFactory.java
@@ -14,13 +14,16 @@
  */
 package org.apache.geode.internal.process;
 
-import org.apache.geode.distributed.internal.DistributionConfig;
+import static org.apache.commons.lang.Validate.isTrue;
+import static org.apache.commons.lang.Validate.notEmpty;
+import static org.apache.commons.lang.Validate.notNull;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
+import org.apache.geode.distributed.internal.DistributionConfig;
+
 /**
  * Manages which implementation of {@link ProcessController} will be used and constructs the
  * instance.
@@ -29,6 +32,9 @@ import java.util.concurrent.TimeoutException;
  */
 public class ProcessControllerFactory {
 
+  /**
+   * For testing only
+   */
   public static final String PROPERTY_DISABLE_ATTACH_API =
       DistributionConfig.GEMFIRE_PREFIX + "test.ProcessControllerFactory.DisableAttachApi";
 
@@ -38,64 +44,44 @@ public class ProcessControllerFactory {
     this.disableAttachApi = Boolean.getBoolean(PROPERTY_DISABLE_ATTACH_API);
   }
 
-  public ProcessController createProcessController(final ProcessControllerParameters arguments,
+  public ProcessController createProcessController(final ProcessControllerParameters parameters,
       final int pid) {
-    if (arguments == null) {
-      throw new NullPointerException("ProcessControllerParameters must not be null");
-    }
-    if (pid < 1) {
-      throw new IllegalArgumentException("Invalid pid '" + pid + "' specified");
-    }
-    try {
-      if (isAttachAPIFound()) {
-        return new MBeanProcessController((MBeanControllerParameters) arguments, pid);
-      } else {
-        return new FileProcessController((FileControllerParameters) arguments, pid);
+    notNull(parameters, "Invalid parameters '" + parameters + "' specified");
+    isTrue(pid > 0, "Invalid pid '" + pid + "' specified");
+
+    if (isAttachAPIFound()) {
+      try {
+        return new MBeanProcessController(parameters, pid);
+      } catch (ExceptionInInitializerError ignore) {
       }
-    } catch (final ExceptionInInitializerError e) {
-      // LOGGER.warn("Attach API class not found", e);
     }
-    return null;
+    return new FileProcessController(parameters, pid);
   }
 
-  public ProcessController createProcessController(final ProcessControllerParameters arguments,
-      final File pidFile, final long timeout, final TimeUnit unit)
+  public ProcessController createProcessController(final ProcessControllerParameters parameters,
+      final File directory, final String pidFileName)
       throws IOException, InterruptedException, TimeoutException {
-    if (arguments == null) {
-      throw new NullPointerException("ProcessControllerParameters must not be null");
-    }
-    if (pidFile == null) {
-      throw new NullPointerException("Pid file must not be null");
-    }
-    return createProcessController(arguments, new PidFile(pidFile).readPid(timeout, unit));
-  }
+    notNull(parameters, "Invalid parameters '" + parameters + "' specified");
+    notNull(directory, "Invalid directory '" + directory + "' specified");
+    notEmpty(pidFileName, "Invalid pidFileName '" + pidFileName + "' specified");
 
-  public ProcessController createProcessController(final ProcessControllerParameters arguments,
-      final File directory, final String pidFilename, final long timeout, final TimeUnit unit)
-      throws IOException, InterruptedException, TimeoutException {
-    if (arguments == null) {
-      throw new NullPointerException("ProcessControllerParameters must not be null");
-    }
-    if (directory == null) {
-      throw new NullPointerException("Directory must not be null");
-    }
-    if (pidFilename == null) {
-      throw new NullPointerException("Pid file name must not be null");
-    }
-    return createProcessController(arguments,
-        new PidFile(directory, pidFilename).readPid(timeout, unit));
+    return createProcessController(parameters, readPid(directory, pidFileName));
   }
 
   public boolean isAttachAPIFound() {
-    if (this.disableAttachApi) {
+    if (disableAttachApi) {
       return false;
     }
     boolean found = false;
     try {
       final Class<?> virtualMachineClass = Class.forName("com.sun.tools.attach.VirtualMachine");
       found = virtualMachineClass != null;
-    } catch (ClassNotFoundException e) {
+    } catch (ClassNotFoundException ignore) {
     }
     return found;
   }
+
+  private int readPid(final File directory, final String pidFileName) throws IOException {
+    return new PidFile(directory, pidFileName).readPid();
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerParameters.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerParameters.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerParameters.java
index eb3deb9..a20faf1 100755
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerParameters.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessControllerParameters.java
@@ -15,10 +15,10 @@
 package org.apache.geode.internal.process;
 
 /**
- * Defines the methods for providing input arguments to the <code>ProcessController</code>.
+ * Defines the methods for providing input arguments to the {@code ProcessController}.
  * 
- * Implementations of <code>ProcessController</code> are in this package. Classes that implement
- * <code>ProcessControllerArguments</code> would typically be in a different package.
+ * Implementations of {@code ProcessController} are in this package. Classes that implement
+ * {@code ProcessController} would typically be in a different package.
  * 
  * @since GemFire 8.0
  */

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/main/java/org/apache/geode/internal/process/ProcessLauncherContext.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessLauncherContext.java b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessLauncherContext.java
index 463fd18..9b10550 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/process/ProcessLauncherContext.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/process/ProcessLauncherContext.java
@@ -12,16 +12,14 @@
  * or implied. See the License for the specific language governing permissions and limitations under
  * the License.
  */
-
 package org.apache.geode.internal.process;
 
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.io.TeeOutputStream;
-import org.apache.geode.internal.io.TeePrintStream;
+import static org.apache.commons.lang.Validate.notNull;
 
-import java.io.*;
 import java.util.Properties;
 
+import org.apache.geode.distributed.internal.DistributionConfig;
+
 /**
  * Thread based context for launching a process. GemFire internals can acquire optional
  * configuration details from a process launcher via this context.
@@ -43,8 +41,11 @@ public class ProcessLauncherContext {
    */
   private static final Properties OVERRIDDEN_DEFAULTS_DEFAULT = new Properties();
 
-  private static final ThreadLocal<ProcessLauncherContext> DATA =
-      new ThreadLocal<ProcessLauncherContext>();
+  private static final ThreadLocal<ProcessLauncherContext> DATA = new ThreadLocal<>();
+
+  private final boolean redirectOutput;
+  private final Properties overriddenDefaults;
+  private final StartupStatusListener startupListener;
 
   private static ProcessLauncherContext get() {
     return DATA.get();
@@ -56,7 +57,7 @@ public class ProcessLauncherContext {
    * @return true if this process should redirect output to the system log
    */
   public static boolean isRedirectingOutput() {
-    final ProcessLauncherContext context = get();
+    ProcessLauncherContext context = get();
     if (context == null) {
       return REDIRECT_OUTPUT_DEFAULT;
     }
@@ -71,16 +72,15 @@ public class ProcessLauncherContext {
    * @return the contingent gemfire properties values to be used as an alternative default value
    */
   public static Properties getOverriddenDefaults() {
-    final ProcessLauncherContext context = get();
+    ProcessLauncherContext context = get();
     if (context == null) {
       return OVERRIDDEN_DEFAULTS_DEFAULT;
     }
     return context.overriddenDefaults();
   }
 
-
   public static StartupStatusListener getStartupListener() {
-    final ProcessLauncherContext context = get();
+    ProcessLauncherContext context = get();
     if (context == null) {
       return null;
     }
@@ -91,9 +91,12 @@ public class ProcessLauncherContext {
   /**
    * Sets the ProcessLauncherContext data for the calling thread.
    */
-  public static void set(final boolean redirectOutput, final Properties contingentProperties,
+  public static void set(final boolean redirectOutput, final Properties overriddenDefaults,
       final StartupStatusListener startupListener) {
-    DATA.set(new ProcessLauncherContext(redirectOutput, contingentProperties, startupListener));
+    notNull(overriddenDefaults,
+        "Invalid overriddenDefaults '" + overriddenDefaults + "' specified");
+
+    DATA.set(new ProcessLauncherContext(redirectOutput, overriddenDefaults, startupListener));
     installLogListener(startupListener);
   }
 
@@ -101,12 +104,11 @@ public class ProcessLauncherContext {
    * Clears the current ProcessLauncherContext for the calling thread.
    */
   public static void remove() {
-    // DATA.get().restoreErrorStream();
     DATA.remove();
     clearLogListener();
   }
 
-  private static void installLogListener(StartupStatusListener startupListener) {
+  private static void installLogListener(final StartupStatusListener startupListener) {
     if (startupListener != null) {
       StartupStatus.setListener(startupListener);
     }
@@ -116,11 +118,6 @@ public class ProcessLauncherContext {
     StartupStatus.clearListener();
   }
 
-  private final boolean redirectOutput;
-  private final Properties overriddenDefaults;
-  private final StartupStatusListener startupListener;
-  private PrintStream err;
-
   private ProcessLauncherContext(final boolean redirectOutput, final Properties overriddenDefaults,
       final StartupStatusListener startupListener) {
     this.redirectOutput = redirectOutput;
@@ -129,39 +126,14 @@ public class ProcessLauncherContext {
   }
 
   private boolean redirectOutput() {
-    return this.redirectOutput;
+    return redirectOutput;
   }
 
   private Properties overriddenDefaults() {
-    return this.overriddenDefaults;
+    return overriddenDefaults;
   }
 
   private StartupStatusListener startupListener() {
-    return this.startupListener;
-  }
-
-  @SuppressWarnings("unused")
-  private void teeErrorStream() {
-    final FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
-    this.err = new PrintStream(new BufferedOutputStream(fdErr, 128), true);
-    System.setErr(new TeePrintStream(new TeeOutputStream(new BufferedOutputStream(fdErr, 128))));
-  }
-
-  @SuppressWarnings("unused")
-  private void restoreErrorStream() {
-    if (System.err instanceof TeePrintStream) {
-      final TeePrintStream tee = ((TeePrintStream) System.err);
-      final OutputStream branch = tee.getTeeOutputStream().getBranchOutputStream();
-
-      PrintStream newStdErr = null;
-      if (branch == null) {
-        newStdErr = this.err;
-      } else if (branch instanceof PrintStream) {
-        newStdErr = (PrintStream) branch;
-      } else {
-        newStdErr = new PrintStream(new BufferedOutputStream(branch, 128), true);
-      }
-      System.setErr(newStdErr);
-    }
+    return startupListener;
   }
 }


[04/23] geode git commit: GEODE-3397: Fixed issue with Tomcat locators in cache-client.xml file

Posted by zh...@apache.org.
GEODE-3397: Fixed issue with Tomcat locators in cache-client.xml file

This closes #688


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/1bd15f8a
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/1bd15f8a
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/1bd15f8a

Branch: refs/heads/feature/GEODE-3304
Commit: 1bd15f8a27b9875d65910bd8ad51bd32122bc002
Parents: 8a6e309
Author: David Anuta <da...@gmail.com>
Authored: Fri Aug 4 13:26:24 2017 -0700
Committer: Jason Huynh <hu...@gmail.com>
Committed: Thu Aug 10 13:11:18 2017 -0700

----------------------------------------------------------------------
 .../geode/session/tests/ContainerInstall.java   | 20 ++++++++++++++++----
 .../geode/session/tests/ServerContainer.java    |  2 +-
 2 files changed, 17 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/1bd15f8a/geode-assembly/src/test/java/org/apache/geode/session/tests/ContainerInstall.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/org/apache/geode/session/tests/ContainerInstall.java b/geode-assembly/src/test/java/org/apache/geode/session/tests/ContainerInstall.java
index 45b8668..9d03417 100644
--- a/geode-assembly/src/test/java/org/apache/geode/session/tests/ContainerInstall.java
+++ b/geode-assembly/src/test/java/org/apache/geode/session/tests/ContainerInstall.java
@@ -419,13 +419,25 @@ public abstract class ContainerInstall {
       DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
       Document doc = docBuilder.parse(XMLPath);
 
+      Node node = null;
       // Get node with specified tagId
-      Node node = findNodeWithAttribute(doc, tagName, "id", tagId);
+      if (tagId != null) {
+        node = findNodeWithAttribute(doc, tagName, "id", tagId);
+      } else if (writeOnSimilarAttributeNames) {
+        NodeList nodes = doc.getElementsByTagName(tagName);
+        for (int i = 0; i < nodes.getLength(); i++) {
+          Node n = nodes.item(i);
+          if (nodeHasExactAttributes(n, attributes, false)) {
+            node = n;
+            break;
+          }
+        }
+      }
       // If no node is found
-      if (node != null
-          || (writeOnSimilarAttributeNames && nodeHasExactAttributes(node, attributes, false))) {
+      if (node != null) {
         rewriteNodeAttributes(node, attributes);
-        ((Element) node).setAttribute("id", tagId);
+        if (tagId != null)
+          ((Element) node).setAttribute("id", tagId);
       } else {
         Element e = doc.createElement(tagName);
         // Set id attribute

http://git-wip-us.apache.org/repos/asf/geode/blob/1bd15f8a/geode-assembly/src/test/java/org/apache/geode/session/tests/ServerContainer.java
----------------------------------------------------------------------
diff --git a/geode-assembly/src/test/java/org/apache/geode/session/tests/ServerContainer.java b/geode-assembly/src/test/java/org/apache/geode/session/tests/ServerContainer.java
index 94a13e9..dbd438a 100644
--- a/geode-assembly/src/test/java/org/apache/geode/session/tests/ServerContainer.java
+++ b/geode-assembly/src/test/java/org/apache/geode/session/tests/ServerContainer.java
@@ -368,7 +368,7 @@ public abstract class ServerContainer {
       attributes.put("port", Integer.toString(locatorPort));
 
       ContainerInstall.editXMLFile(getSystemProperty("cache-xml-file"), "locator", "pool",
-          attributes);
+          attributes, true);
     } else {
       setSystemProperty("locators", locatorAddress + "[" + locatorPort + "]");
     }


[11/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java
new file mode 100755
index 0000000..d22d92a
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.lang.SystemUtils.isWindows;
+import static org.apache.geode.internal.process.ProcessStreamReader.ReadingMode.BLOCKING;
+import static org.junit.Assume.assumeFalse;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for BlockingProcessStreamReader. All tests are skipped on Windows
+ * due to TRAC #51967: "GFSH start hangs on Windows"
+ *
+ * @see BlockingProcessStreamReaderWindowsTest
+ * @see NonBlockingProcessStreamReaderIntegrationTest
+ *
+ * @since GemFire 8.2
+ */
+@Category(IntegrationTest.class)
+public class BlockingProcessStreamReaderIntegrationTest
+    extends BaseProcessStreamReaderIntegrationTest {
+
+  @Before
+  public void setUp() throws Exception {
+    assumeFalse(isWindows());
+  }
+
+  @Test
+  public void canCloseStreams() throws Exception {
+    // arrange
+    givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+    // act
+    process.getOutputStream().close();
+    process.getErrorStream().close();
+    process.getInputStream().close();
+
+    // assert
+    assertThatProcessIsAlive(process);
+  }
+
+  @Test
+  public void canStopReaders() throws Exception {
+    // arrange
+    givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+    // act
+    stdout.stop();
+    stderr.stop();
+
+    // assert
+    assertThatProcessIsAlive(process);
+  }
+
+  @Test
+  public void capturesStdout() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessPrintsToStdout.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStopped();
+    assertThatStdOutContainsExactly(ProcessPrintsToStdout.STDOUT);
+    assertThatStdErrContainsExactly(ProcessPrintsToStdout.STDERR);
+  }
+
+  @Test
+  public void capturesStderr() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessPrintsToStderr.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStopped();
+    assertThatStdOutContainsExactly(ProcessPrintsToStderr.STDOUT);
+    assertThatStdErrContainsExactly(ProcessPrintsToStderr.STDERR);
+  }
+
+  @Test
+  public void capturesStdoutAndStderr() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessPrintsToBoth.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStopped();
+    assertThatStdOutContainsExactly(ProcessPrintsToBoth.STDOUT);
+    assertThatStdErrContainsExactly(ProcessPrintsToBoth.STDERR);
+  }
+
+  @Test
+  public void capturesStderrWhenProcessFailsDuringStart() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessThrowsError.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStoppedWithExitValue(1);
+    assertThatStdOutContainsExactly(ProcessThrowsError.STDOUT);
+    assertThatStdErrContains(ProcessThrowsError.ERROR_MSG);
+  }
+
+  @Override
+  protected ReadingMode getReadingMode() {
+    return BLOCKING;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java
deleted file mode 100755
index 7d52e56..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-
-import java.io.IOException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.internal.lang.SystemUtils;
-import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
-import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * Tests BlockingProcessStreamReader. Most tests are skipped on Windows due to TRAC bug #51967 which
- * is caused by a JDK bug. The test {@link #hangsOnWindows} verifies the existence of the bug.
- * 
- * @since GemFire 8.2
- */
-@Category(IntegrationTest.class)
-public class BlockingProcessStreamReaderJUnitTest extends ProcessStreamReaderTestCase {
-
-  /** Timeout to confirm hang on Windows */
-  private static final int HANG_TIMEOUT = 10;
-
-  private ExecutorService futures;
-
-  @Before
-  public void createFutures() {
-    this.futures = Executors.newSingleThreadExecutor();
-  }
-
-  @After
-  public void shutdownFutures() {
-    assertTrue(this.futures.shutdownNow().isEmpty());
-  }
-
-  @Test
-  public void hangsOnWindows() throws Exception {
-    assumeTrue(SystemUtils.isWindows());
-
-    this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
-    this.stderr = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build();
-
-    this.stdout = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    assertIsAlive(this.process);
-
-    assertEventuallyIsRunning(this.stderr);
-    assertEventuallyIsRunning(this.stdout);
-
-    Future<Boolean> future = this.futures.submit(new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws IOException {
-        process.getErrorStream().close();
-        process.getOutputStream().close();
-        process.getInputStream().close();
-        return true;
-      }
-    });
-
-    try {
-      future.get(HANG_TIMEOUT, TimeUnit.SECONDS);
-      // if the following fails then perhaps we're testing with a new JRE that
-      // fixes blocking reads of process streams on windows
-      fail("future should have timedout due to hang on windows");
-    } catch (TimeoutException expected) {
-      // verified hang on windows which causes TRAC bug #51967
-    }
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void canCloseStreamsWhileProcessIsAlive() throws Exception {
-    assumeFalse(SystemUtils.isWindows());
-
-    this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
-    this.stderr = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build();
-
-    this.stdout = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    assertIsAlive(this.process);
-
-    assertEventuallyIsRunning(this.stderr);
-    assertEventuallyIsRunning(this.stdout);
-
-    this.process.getErrorStream().close();
-    this.process.getOutputStream().close();
-    this.process.getInputStream().close();
-
-    assertIsAlive(this.process);
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void canStopReadersWhileProcessIsAlive() throws Exception {
-    assumeFalse(SystemUtils.isWindows());
-
-    this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
-    this.stderr = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build();
-
-    this.stdout = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    assertIsAlive(this.process);
-
-    assertEventuallyIsRunning(this.stderr);
-    assertEventuallyIsRunning(this.stdout);
-
-    this.stderr.stop();
-    this.stdout.stop();
-
-    this.process.getErrorStream().close();
-    this.process.getOutputStream().close();
-    this.process.getInputStream().close();
-
-    assertIsAlive(this.process);
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesStdoutWhileProcessIsAlive() throws Exception {
-    assumeFalse(SystemUtils.isWindows());
-
-    this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStdout.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    assertEventuallyIsRunning(this.stderr);
-    assertEventuallyIsRunning(this.stdout);
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    assertEquals("", stderrBuffer.toString());
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-    StringBuilder sb = new StringBuilder().append(ProcessPrintsToStdout.LINES[0])
-        .append(ProcessPrintsToStdout.LINES[1]).append(ProcessPrintsToStdout.LINES[2]);
-    assertEquals(sb.toString(), stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesStderrWhileProcessIsAlive() throws Exception {
-    assumeFalse(SystemUtils.isWindows());
-
-    this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStderr.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    StringBuilder sb = new StringBuilder().append(ProcessPrintsToStderr.LINES[0])
-        .append(ProcessPrintsToStderr.LINES[1]).append(ProcessPrintsToStderr.LINES[2]);
-    assertEquals(sb.toString(), stderrBuffer.toString());
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-    assertEquals("", stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesBothWhileProcessIsAlive() throws Exception {
-    assumeFalse(SystemUtils.isWindows());
-
-    this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToBoth.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    StringBuilder sb = new StringBuilder().append(ProcessPrintsToBoth.ERR_LINES[0])
-        .append(ProcessPrintsToBoth.ERR_LINES[1]).append(ProcessPrintsToBoth.ERR_LINES[2]);
-    assertEquals(sb.toString(), stderrBuffer.toString());
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-    sb = new StringBuilder().append(ProcessPrintsToBoth.OUT_LINES[0])
-        .append(ProcessPrintsToBoth.OUT_LINES[1]).append(ProcessPrintsToBoth.OUT_LINES[2]);
-    assertEquals(sb.toString(), stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesStderrWhenProcessFailsDuringStart() throws Exception {
-    assumeFalse(SystemUtils.isWindows());
-
-    this.process = new ProcessBuilder(createCommandLine(ProcessThrowsError.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertNotEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    assertTrue(stderrBuffer.toString() + " does not contain " + ProcessThrowsError.ERROR_MSG,
-        stderrBuffer.toString().contains(ProcessThrowsError.ERROR_MSG));
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java
new file mode 100644
index 0000000..60c94e4
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.internal.lang.SystemUtils.isWindows;
+import static org.apache.geode.internal.process.ProcessStreamReader.ReadingMode.BLOCKING;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration test {@link #hangsOnWindows} for BlockingProcessStreamReader which
+ * verifies TRAC #51967: "GFSH start hangs on Windows." The hang is supposedly caused by a JDK bug
+ * in which a thread invoking readLine() will block forever and ignore any interrupts. The thread
+ * will respond to interrupts as expected on Mac, Linux and Solaris.
+ *
+ * @see BlockingProcessStreamReaderIntegrationTest
+ * @see NonBlockingProcessStreamReaderIntegrationTest
+ *
+ * @since GemFire 8.2
+ */
+@Category(IntegrationTest.class)
+public class BlockingProcessStreamReaderWindowsTest
+    extends AbstractProcessStreamReaderIntegrationTest {
+
+  /** Timeout to confirm hang on Windows */
+  private static final int HANG_TIMEOUT_SECONDS = 10;
+
+  private ExecutorService futures;
+
+  @Before
+  public void setUp() throws Exception {
+    assumeTrue(isWindows());
+
+    futures = Executors.newSingleThreadExecutor();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (futures != null) {
+      assertThat(futures.shutdownNow()).isEmpty();
+    }
+  }
+
+  @Test
+  public void hangsOnWindows() throws Exception {
+    // arrange
+    givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+    // act
+    Future<Boolean> future = futures.submit(() -> {
+      process.getOutputStream().close();
+      process.getErrorStream().close();
+      process.getInputStream().close();
+      return true;
+    });
+
+    // assert
+    assertThatThrownBy(() -> future.get(HANG_TIMEOUT_SECONDS, SECONDS))
+        .isInstanceOf(TimeoutException.class);
+  }
+
+  @Override
+  protected ReadingMode getReadingMode() {
+    return BLOCKING;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java
new file mode 100644
index 0000000..46c81f7
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.awaitility.Awaitility.await;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for {@link ControlFileWatchdog}.
+ */
+@Category(IntegrationTest.class)
+public class ControlFileWatchdogIntegrationTest {
+
+  private static final int TWO_MINUTES_MILLIS = 2 * 60 * 1000;
+
+  private File directory;
+  private String requestFileName;
+  private File requestFile;
+  private ControlRequestHandler requestHandler;
+  private boolean stopAfterRequest;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Before
+  public void before() throws Exception {
+    directory = temporaryFolder.getRoot();
+    requestFileName = "myFile";
+    requestFile = new File(directory, requestFileName);
+    requestHandler = mock(ControlRequestHandler.class);
+    stopAfterRequest = false;
+  }
+
+  @Test
+  public void isAlive_returnsFalse_beforeStart() throws Exception {
+    // arrange
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+    // act: nothing
+
+    // assert
+    assertThat(watchdog.isAlive()).isFalse();
+  }
+
+  @Test
+  public void isAlive_returnsTrue_afterStart() throws Exception {
+    // arrange
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+    // act
+    watchdog.start();
+
+    // assert
+    assertThat(watchdog.isAlive()).isTrue();
+  }
+
+  @Test
+  public void isAlive_returnsFalse_afterStop() throws Exception {
+    // arrange
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+    watchdog.start();
+
+    // act
+    watchdog.stop();
+
+    // assert
+    assertThat(watchdog.isAlive()).isFalse();
+  }
+
+  @Test
+  public void nullFileName_throwsIllegalArgumentException() throws Exception {
+    // arrange
+    requestFileName = null;
+
+    // act/assert
+    assertThatThrownBy(
+        () -> new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest))
+            .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void nullDirectory_throwsIllegalArgumentException() throws Exception {
+    // arrange
+    directory = null;
+
+    // act/assert
+    assertThatThrownBy(
+        () -> new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest))
+            .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void nullRequestHandler_throwsIllegalArgumentException() throws Exception {
+    // arrange
+    requestHandler = null;
+
+    // act/assert
+    assertThatThrownBy(
+        () -> new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest))
+            .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void invokesRequestHandler_afterFileCreation() throws Exception {
+    // arrange
+    requestHandler = mock(ControlRequestHandler.class);
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+    watchdog.start();
+
+    // act
+    File file = new EmptyFileWriter(requestFile).createNewFile();
+
+    // assert
+    verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+    assertThat(file).doesNotExist();
+  }
+
+  @Test
+  public void deletesFile_afterInvokingRequestHandler() throws Exception {
+    // arrange
+    requestHandler = mock(ControlRequestHandler.class);
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+    watchdog.start();
+
+    // act
+    File file = new EmptyFileWriter(requestFile).createNewFile();
+
+    // assert
+    verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+    await().atMost(2, MINUTES).until(() -> assertThat(file).doesNotExist());
+    assertThat(file).doesNotExist();
+  }
+
+  @Test
+  public void doesNotInvokeRequestHandler_whileFileDoesNotExist() throws Exception {
+    // arrange
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+    // act
+    watchdog.start();
+
+    // assert
+    verifyZeroInteractions(requestHandler); // would be prefer to wait some time
+  }
+
+  @Test
+  public void nothingHappens_beforeStart() throws Exception {
+    // arrange
+    requestHandler = mock(ControlRequestHandler.class);
+    new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+    // act
+    File file = new EmptyFileWriter(requestFile).createNewFile();
+
+    // assert
+    verifyZeroInteractions(requestHandler); // would be prefer to wait some time
+    assertThat(file).exists();
+  }
+
+  @Test
+  public void stops_afterInvokingRequestHandler_whenStopAfterRequest() throws Exception {
+    // arrange
+    requestHandler = mock(ControlRequestHandler.class);
+    stopAfterRequest = true;
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+    watchdog.start();
+
+    // act
+    File file = new EmptyFileWriter(requestFile).createNewFile();
+
+    // assert
+    verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+    await().atMost(2, MINUTES).until(() -> assertThat(watchdog.isAlive()).isFalse());
+    assertThat(file).doesNotExist();
+  }
+
+  @Test
+  public void doesNotStop_afterInvokingRequestHandler_whenNotStopAfterRequest() throws Exception {
+    // arrange
+    requestHandler = mock(ControlRequestHandler.class);
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+    watchdog.start();
+
+    // act
+    File file = new EmptyFileWriter(requestFile).createNewFile();
+
+    // assert
+    verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+    assertThat(watchdog.isAlive()).isTrue();
+    assertThat(file).doesNotExist();
+  }
+
+  @Test
+  public void toStringIsUsefulForDebugging() throws Exception {
+    // arrange
+    ControlFileWatchdog watchdog =
+        new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+    // act/assert
+    assertThat(watchdog.toString()).isNotEmpty().contains("directory=").contains("file=")
+        .contains("alive=").contains("stopAfterRequest=");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java
new file mode 100644
index 0000000..903f08f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.distributed.AbstractLauncher.ServiceState;
+import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class ControllableProcessIntegrationTest {
+
+  private LocalProcessLauncher localProcessLauncher;
+  private ControlFileWatchdog stopRequestFileWatchdog;
+  private ControlFileWatchdog statusRequestFileWatchdog;
+  private ProcessType processType;
+  private File directory;
+  private File pidFile;
+  private int pid;
+  private File statusRequestFile;
+  private File stopRequestFile;
+  private File statusFile;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Before
+  public void before() throws Exception {
+    processType = ProcessType.LOCATOR;
+    directory = temporaryFolder.getRoot();
+    pidFile = new File(directory, processType.getPidFileName());
+    pid = identifyPid();
+    statusRequestFile = new File(directory, processType.getStatusRequestFileName());
+    stopRequestFile = new File(directory, processType.getStopRequestFileName());
+    statusFile = new File(directory, processType.getStatusFileName());
+    statusRequestFileWatchdog = new ControlFileWatchdog(directory,
+        processType.getStatusRequestFileName(), mock(ControlRequestHandler.class), false);
+    stopRequestFileWatchdog = new ControlFileWatchdog(directory,
+        processType.getStopRequestFileName(), mock(ControlRequestHandler.class), false);
+  }
+
+  @Test
+  public void getDirectoryExists() throws Exception {
+    // arrange
+    localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+    // act
+    ControllableProcess controllable = new ControllableProcess(directory, processType,
+        localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+    // assert
+    assertThat(controllable.getDirectory()).isEqualTo(directory);
+  }
+
+  @Test
+  public void creationDeletesStatusRequestFileInDirectory() throws Exception {
+    // arrange
+    localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+    File file = new EmptyFileWriter(statusRequestFile).createNewFile();
+
+    // act
+    new ControllableProcess(directory, processType, localProcessLauncher, stopRequestFileWatchdog,
+        statusRequestFileWatchdog);
+
+    // assert
+    assertThat(file).doesNotExist();
+  }
+
+  @Test
+  public void creationDeletesStatusResponseFileInDirectory() throws Exception {
+    // arrange
+    localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+    File file = new EmptyFileWriter(statusFile).createNewFile();
+
+    // act
+    new ControllableProcess(directory, processType, localProcessLauncher, stopRequestFileWatchdog,
+        statusRequestFileWatchdog);
+
+    // assert
+    assertThat(file).doesNotExist();
+  }
+
+  @Test
+  public void creationDeletesStopRequestFileInDirectory() throws Exception {
+    // arrange
+    localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+    File file = new EmptyFileWriter(stopRequestFile).createNewFile();
+
+    // act
+    new ControllableProcess(directory, processType, localProcessLauncher, stopRequestFileWatchdog,
+        statusRequestFileWatchdog);
+
+    // assert
+    assertThat(file).doesNotExist();
+  }
+
+  @Test
+  public void getPidReturnsPid() throws Exception {
+    // arrange
+    localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+    // act
+    ControllableProcess controllable = new ControllableProcess(directory, processType,
+        localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+    // assert
+    assertThat(controllable.getPid()).isEqualTo(pid);
+  }
+
+  @Test
+  public void getPidFileExists() throws Exception {
+    // arrange
+    localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+    // act
+    ControllableProcess controllable = new ControllableProcess(directory, processType,
+        localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+    // assert
+    assertThat(controllable.getPidFile()).exists().hasContent(String.valueOf(pid));
+  }
+
+  @Test
+  public void stopsBothControlFileWatchdogs() throws Exception {
+    // arrange
+    ControlFileWatchdog stopRequestFileWatchdog = new ControlFileWatchdog(directory,
+        "stopRequestFile", mock(ControlRequestHandler.class), false);
+    ControlFileWatchdog statusRequestFileWatchdog = new ControlFileWatchdog(directory,
+        "statusRequestFile", mock(ControlRequestHandler.class), false);
+
+    stopRequestFileWatchdog = spy(stopRequestFileWatchdog);
+    statusRequestFileWatchdog = spy(statusRequestFileWatchdog);
+
+    localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+    ControllableProcess controllable = new ControllableProcess(directory, processType,
+        localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+    // act
+    controllable.stop();
+
+    // assert
+    verify(stopRequestFileWatchdog).stop();
+    verify(statusRequestFileWatchdog).stop();
+  }
+
+  @Test
+  public void statusRequestFileIsDeletedAndStatusFileIsCreated() throws Exception {
+    // arrange
+    File statusRequestFile = new File(directory, processType.getStatusRequestFileName());
+    File statusFile = new File(directory, processType.getStatusFileName());
+
+    ServiceState mockServiceState = mock(ServiceState.class);
+    when(mockServiceState.toJson()).thenReturn("json");
+    ControlNotificationHandler mockHandler = mock(ControlNotificationHandler.class);
+    when(mockHandler.handleStatus()).thenReturn(mockServiceState);
+    new ControllableProcess(mockHandler, directory, processType, false);
+
+    // act
+    boolean created = statusRequestFile.createNewFile();
+
+    // assert
+    assertThat(created).isTrue();
+    await().atMost(2, MINUTES).until(() -> assertThat(statusRequestFile).doesNotExist());
+    assertThat(statusFile).exists();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java
deleted file mode 100755
index 6ed12d4..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static com.googlecode.catchexception.CatchException.*;
-import static org.awaitility.Awaitility.*;
-import static java.util.concurrent.TimeUnit.*;
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
-import static org.hamcrest.Matchers.*;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestName;
-
-import org.apache.geode.distributed.LocatorLauncher;
-import org.apache.geode.distributed.AbstractLauncher.Status;
-import org.apache.geode.distributed.LocatorLauncher.Builder;
-import org.apache.geode.distributed.LocatorLauncher.LocatorState;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * Integration tests for FileProcessController.
- */
-@Category(IntegrationTest.class)
-public class FileProcessControllerIntegrationJUnitTest {
-
-  private ProcessType processType;
-  private ExecutorService executor;
-
-  @Rule
-  public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
-  @Rule
-  public TestName testName = new TestName();
-
-  @Before
-  public void setUp() throws Exception {
-    this.processType = ProcessType.LOCATOR;
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    if (this.executor != null) {
-      this.executor.shutdownNow();
-    }
-  }
-
-  @Test
-  public void statusShouldAwaitTimeoutWhileFileIsEmpty() throws Exception {
-    // given: FileProcessController with empty pidFile
-    int pid = ProcessUtils.identifyPid();
-    File emptyPidFile = this.temporaryFolder.newFile(this.processType.getPidFileName());
-    FileControllerParameters params = mock(FileControllerParameters.class);
-    when(params.getPidFile()).thenReturn(emptyPidFile);
-    when(params.getProcessId()).thenReturn(pid);
-    when(params.getProcessType()).thenReturn(this.processType);
-    when(params.getWorkingDirectory()).thenReturn(this.temporaryFolder.getRoot());
-
-    FileProcessController controller = new FileProcessController(params, 1, 10, MILLISECONDS);
-
-    // when
-    verifyException(controller).status();
-
-    // then: we expect TimeoutException to be thrown
-    assertThat((Exception) caughtException()).isInstanceOf(TimeoutException.class)
-        .hasMessageContaining("Timed out waiting for process to create").hasNoCause();
-  }
-
-  @Test
-  public void statusShouldReturnJsonFromStatusFile() throws Exception {
-    // given: FileProcessController with pidFile containing real pid
-    int pid = ProcessUtils.identifyPid();
-    File pidFile = this.temporaryFolder.newFile(this.processType.getPidFileName());
-    writeToFile(pidFile, String.valueOf(pid));
-
-    FileControllerParameters params = mock(FileControllerParameters.class);
-    when(params.getPidFile()).thenReturn(pidFile);
-    when(params.getProcessId()).thenReturn(pid);
-    when(params.getProcessType()).thenReturn(this.processType);
-    when(params.getWorkingDirectory()).thenReturn(this.temporaryFolder.getRoot());
-
-    FileProcessController controller = new FileProcessController(params, pid, 1, MINUTES);
-
-    // when: status is called in one thread and json is written to the file
-    AtomicReference<String> status = new AtomicReference<String>();
-    AtomicReference<Exception> exception = new AtomicReference<Exception>();
-    this.executor = Executors.newSingleThreadExecutor();
-    this.executor.execute(new Runnable() {
-      @Override
-      public void run() {
-        try {
-          status.set(controller.status());
-        } catch (Exception e) {
-          exception.set(e);
-        }
-      }
-    });
-
-    // write status
-    String statusJson = generateStatusJson();
-    File statusFile = this.temporaryFolder.newFile(this.processType.getStatusFileName());
-    writeToFile(statusFile, statusJson);
-
-    // then: returned status should be the json in the file
-    assertThat(exception.get()).isNull();
-    with().pollInterval(10, MILLISECONDS).await().atMost(2, MINUTES).untilAtomic(status,
-        equalTo(statusJson));
-    assertThat(status.get()).isEqualTo(statusJson);
-    System.out.println(statusJson);
-  }
-
-  private static void writeToFile(final File file, final String value) throws IOException {
-    final FileWriter writer = new FileWriter(file);
-    writer.write(value);
-    writer.flush();
-    writer.close();
-  }
-
-  private static String generateStatusJson() {
-    Builder builder = new Builder();
-    LocatorLauncher defaultLauncher = builder.build();
-    Status status = Status.ONLINE;
-    LocatorState locatorState = new LocatorState(defaultLauncher, status);
-    return locatorState.toJson();
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java
new file mode 100755
index 0000000..6eda29f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static com.googlecode.catchexception.CatchException.caughtException;
+import static com.googlecode.catchexception.CatchException.verifyException;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ErrorCollector;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import org.apache.geode.distributed.AbstractLauncher.Status;
+import org.apache.geode.distributed.LocatorLauncher;
+import org.apache.geode.distributed.LocatorLauncher.Builder;
+import org.apache.geode.distributed.LocatorLauncher.LocatorState;
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.internal.process.io.IntegerFileWriter;
+import org.apache.geode.internal.process.io.StringFileWriter;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Integration tests for {@link FileProcessController}.
+ *
+ * <p>
+ * This test shows one of the more appropriate uses of ErrorCollector Rule -- catching any failed
+ * assertions in another thread that isn't the main JUnit thread.
+ */
+@Category(IntegrationTest.class)
+public class FileProcessControllerIntegrationTest {
+
+  private static final String STATUS_JSON = generateStatusJson();
+
+  private final AtomicReference<String> statusRef = new AtomicReference<>();
+
+  private File pidFile;
+  private File statusFile;
+  private File statusRequestFile;
+  private File stopRequestFile;
+  private int pid;
+  private FileControllerParameters params;
+  private ExecutorService executor;
+
+  @Rule
+  public ErrorCollector errorCollector = new ErrorCollector();
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @Before
+  public void setUp() throws Exception {
+    ProcessType processType = ProcessType.LOCATOR;
+    File directory = temporaryFolder.getRoot();
+    pidFile = new File(directory, processType.getPidFileName());
+    statusFile = new File(directory, processType.getStatusFileName());
+    statusRequestFile = new File(directory, processType.getStatusRequestFileName());
+    stopRequestFile = new File(directory, processType.getStopRequestFileName());
+    pid = ProcessUtils.identifyPid();
+
+    params = mock(FileControllerParameters.class);
+    when(params.getPidFile()).thenReturn(pidFile);
+    when(params.getProcessId()).thenReturn(pid);
+    when(params.getProcessType()).thenReturn(processType);
+    when(params.getDirectory()).thenReturn(temporaryFolder.getRoot());
+
+    executor = Executors.newSingleThreadExecutor();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    assertThat(executor.shutdownNow()).isEmpty();
+  }
+
+  @Test
+  public void statusShouldAwaitTimeoutWhileFileIsEmpty() throws Exception {
+    // given: FileProcessController with empty pidFile
+    FileProcessController controller = new FileProcessController(params, pid, 10, MILLISECONDS);
+
+    // when:
+    verifyException(controller).status();
+
+    // then: we expect TimeoutException to be thrown
+    assertThat((Exception) caughtException()).isInstanceOf(TimeoutException.class)
+        .hasMessageContaining("Timed out waiting for process to create").hasNoCause();
+  }
+
+  @Test
+  public void statusShouldReturnJsonFromStatusFile() throws Exception {
+    // given: FileProcessController with pidFile containing real pid
+    new IntegerFileWriter(pidFile).writeToFile(pid);
+    FileProcessController controller = new FileProcessController(params, pid, 2, MINUTES);
+
+    // when: status is called in one thread
+    executor.execute(() -> {
+      try {
+        statusRef.set(controller.status());
+      } catch (Exception e) {
+        errorCollector.addError(e);
+      }
+    });
+
+    // and: json is written to the status file
+    new StringFileWriter(statusFile).writeToFile(STATUS_JSON);
+
+    // then: returned status should be the json in the file
+    await().until(() -> assertThat(statusRef.get()).isEqualTo(STATUS_JSON));
+  }
+
+  /**
+   * This is a new test written for GEODE-3413: "Overhaul launcher tests and process tests."
+   * Unfortunately, it hangs so I have filed GEODE-3278. This test should be used to fix and verify
+   * that bug.
+   */
+  @Ignore("GEODE-3278: Empty status file causes status server and status locator to hang")
+  @Test
+  public void emptyStatusFileCausesStatusToHang() throws Exception {
+    // given: FileProcessController with pidFile containing real pid
+    new IntegerFileWriter(pidFile).writeToFile(pid);
+    FileProcessController controller = new FileProcessController(params, pid, 2, MINUTES);
+
+    // when: status is called in one thread
+    executor.execute(() -> {
+      try {
+        statusRef.set(controller.status());
+      } catch (Exception e) {
+        errorCollector.addError(e);
+      }
+    });
+
+    // and: json is written to the status file
+    new EmptyFileWriter(statusFile).createNewFile();
+
+    // then: returned status should be the json in the file
+    await().until(() -> assertThat(statusRef.get()).isEqualTo(STATUS_JSON));
+  }
+
+  @Test
+  public void stopCreatesStopRequestFile() throws Exception {
+    // arrange
+    FileProcessController controller = new FileProcessController(params, pid);
+    assertThat(stopRequestFile).doesNotExist();
+
+    // act
+    controller.stop();
+
+    // assert
+    assertThat(stopRequestFile).exists();
+  }
+
+  @Test
+  public void stop_withStopRequestFileExists_doesNotFail() throws Exception {
+    // arrange
+    FileProcessController controller = new FileProcessController(params, pid);
+    assertThat(stopRequestFile.createNewFile()).isTrue();
+
+    // act
+    controller.stop();
+
+    // assert
+    assertThat(stopRequestFile).exists();
+  }
+
+  @Test
+  public void status_withStatusRequestFileExists_doesNotFail() throws Exception {
+    // arrange
+    FileProcessController controller = new FileProcessController(params, pid);
+    assertThat(statusRequestFile.createNewFile()).isTrue();
+
+    // act
+    executor.execute(() -> {
+      try {
+        statusRef.set(controller.status());
+      } catch (Exception e) {
+        errorCollector.addError(e);
+      }
+    });
+
+    new StringFileWriter(statusFile).writeToFile(STATUS_JSON);
+
+    // assert
+    assertThat(statusRequestFile).exists();
+  }
+
+  @Test
+  public void statusCreatesStatusRequestFile() throws Exception {
+    // arrange
+    new IntegerFileWriter(pidFile).writeToFile(pid);
+    FileProcessController controller = new FileProcessController(params, pid, 2, MINUTES);
+
+    // act
+    executor.execute(() -> {
+      try {
+        assertThatThrownBy(() -> statusRef.set(controller.status()))
+            .isInstanceOf(InterruptedException.class);
+      } catch (Throwable t) {
+        errorCollector.addError(t);
+      }
+    });
+
+    // assert
+    await().until(() -> assertThat(statusRequestFile).exists());
+  }
+
+  private ConditionFactory await() {
+    return Awaitility.await().atMost(2, MINUTES);
+  }
+
+  private static String generateStatusJson() {
+    Builder builder = new Builder();
+    LocatorLauncher defaultLauncher = builder.build();
+    Status status = Status.ONLINE;
+    LocatorState locatorState = new LocatorState(defaultLauncher, status);
+    return locatorState.toJson();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java
new file mode 100644
index 0000000..b742e1b
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.internal.process.FileProcessController.DEFAULT_STATUS_TIMEOUT_MILLIS;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.lang.AttachAPINotFoundException;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link FileProcessController}.
+ */
+@Category(UnitTest.class)
+public class FileProcessControllerTest {
+
+  private FileProcessController controller;
+  private FileControllerParameters mockParameters;
+  private int pid;
+  private long timeout;
+  private TimeUnit units;
+
+  @Before
+  public void before() throws Exception {
+    mockParameters = mock(FileControllerParameters.class);
+    pid = identifyPid();
+    timeout = 0;
+    units = SECONDS;
+
+    controller = new FileProcessController(mockParameters, pid, timeout, units);
+  }
+
+  @Test
+  public void pidLessThanOne_throwsIllegalArgumentException() throws Exception {
+    pid = 0;
+
+    assertThatThrownBy(() -> new FileProcessController(mockParameters, pid, timeout, units))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Invalid pid '" + pid + "' specified");
+  }
+
+  @Test
+  public void getProcessId_returnsPid() throws Exception {
+    assertThat(controller.getProcessId()).isEqualTo(pid);
+  }
+
+  @Test
+  public void checkPidSupport_throwsAttachAPINotFoundException() throws Exception {
+    assertThatThrownBy(() -> controller.checkPidSupport())
+        .isInstanceOf(AttachAPINotFoundException.class);
+  }
+
+  @Test
+  public void statusTimeoutMillis_defaultsToOneMinute() throws Exception {
+    FileProcessController controller = new FileProcessController(mockParameters, pid);
+
+    assertThat(controller.getStatusTimeoutMillis()).isEqualTo(DEFAULT_STATUS_TIMEOUT_MILLIS);
+  }
+
+  @Test
+  public void timeoutLessThanZero_throwsIllegalArgumentException() throws Exception {
+    timeout = -1;
+
+    assertThatThrownBy(() -> new FileProcessController(mockParameters, pid, timeout, units))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Invalid timeout '" + timeout + "' specified");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java
deleted file mode 100755
index b132647..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
-
-import javax.management.MBeanAttributeInfo;
-import javax.management.MBeanInfo;
-import javax.management.MBeanOperationInfo;
-import javax.management.MBeanServer;
-import javax.management.ObjectInstance;
-import javax.management.ObjectName;
-import javax.management.Query;
-import javax.management.QueryExp;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
-
-import org.apache.geode.internal.process.mbean.Process;
-import org.apache.geode.test.junit.categories.UnitTest;
-
-/**
- * Unit tests for LocalProcessController.
- * 
- * @since GemFire 7.0
- */
-@Category(UnitTest.class)
-public class LocalProcessControllerJUnitTest {
-
-  private MBeanServer server;
-  private ObjectName objectName;
-  private int pid;
-
-  @Rule
-  public TestName testName = new TestName();
-
-  @Before
-  public void setUp() throws Exception {
-    pid = ProcessUtils.identifyPid();
-    final Process process = new Process(pid, true);
-
-    this.objectName = ObjectName
-        .getInstance(getClass().getSimpleName() + ":testName=" + testName.getMethodName());
-    this.server = ManagementFactory.getPlatformMBeanServer();
-
-    final ObjectInstance instance = this.server.registerMBean(process, objectName);
-    assertNotNull(instance);
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    this.server.unregisterMBean(objectName);
-  }
-
-  @Test
-  public void testProcessMBean() throws Exception {
-    // validate basics of the ProcessMBean
-    Set<ObjectName> mbeanNames = this.server.queryNames(objectName, null);
-    assertFalse("Zero matching mbeans", mbeanNames.isEmpty());
-    assertEquals(1, mbeanNames.size());
-    final ObjectName name = mbeanNames.iterator().next();
-
-    final MBeanInfo info = this.server.getMBeanInfo(name);
-
-    final MBeanOperationInfo[] operInfo = info.getOperations();
-    assertEquals(1, operInfo.length);
-    assertEquals("stop", operInfo[0].getName());
-
-    final MBeanAttributeInfo[] attrInfo = info.getAttributes();
-    assertEquals(2, attrInfo.length);
-    // The order of these attributes is indeterminate
-    assertTrue("Pid".equals(attrInfo[0].getName()) || "Process".equals(attrInfo[0].getName()));
-    assertTrue("Pid".equals(attrInfo[1].getName()) || "Process".equals(attrInfo[1].getName()));
-    assertNotNull(this.server.getAttribute(name, "Pid"));
-    assertNotNull(this.server.getAttribute(name, "Process"));
-
-    assertEquals(pid, this.server.getAttribute(name, "Pid"));
-    assertEquals(true, this.server.getAttribute(name, "Process"));
-
-    // validate query using only Pid attribute
-    QueryExp constraint = Query.eq(Query.attr("Pid"), Query.value(pid));
-    mbeanNames = this.server.queryNames(objectName, constraint);
-    assertFalse("Zero matching mbeans", mbeanNames.isEmpty());
-
-    // validate query with wrong Pid finds nothing
-    constraint = Query.eq(Query.attr("Pid"), Query.value(pid + 1));
-    mbeanNames = this.server.queryNames(objectName, constraint);
-    assertTrue("Found matching mbeans", mbeanNames.isEmpty());
-
-    // validate query using both attributes
-    constraint = Query.and(Query.eq(Query.attr("Process"), Query.value(true)),
-        Query.eq(Query.attr("Pid"), Query.value(pid)));
-    mbeanNames = this.server.queryNames(objectName, constraint);
-    assertFalse("Zero matching mbeans", mbeanNames.isEmpty());
-
-    // validate query with wrong attribute finds nothing
-    constraint = Query.and(Query.eq(Query.attr("Process"), Query.value(false)),
-        Query.eq(Query.attr("Pid"), Query.value(pid)));
-    mbeanNames = this.server.queryNames(objectName, constraint);
-    assertTrue("Found matching mbeans", mbeanNames.isEmpty());
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java
deleted file mode 100755
index e1f3e6e..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.SerializableRunnable;
-import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
-import org.apache.geode.test.junit.categories.DistributedTest;
-
-/**
- * Multi-process tests for ProcessLauncher.
- * 
- * @since GemFire 7.0
- */
-@Category(DistributedTest.class)
-@SuppressWarnings("serial")
-public class LocalProcessLauncherDUnitTest extends JUnit4DistributedTestCase {
-
-  public LocalProcessLauncherDUnitTest() {
-    super();
-  }
-
-  @Override
-  public final void postSetUp() throws Exception {
-    new File(getClass().getSimpleName()).mkdir();
-  }
-
-  @Test
-  public void testExistingPidFileThrows() throws Exception {
-    final File pidFile =
-        new File(getClass().getSimpleName() + File.separator + "testExistingPidFileThrows.pid");
-    final String absolutePath = pidFile.getAbsolutePath();
-
-    assertFalse(pidFile.exists());
-    new LocalProcessLauncher(pidFile, false);
-    assertTrue(pidFile.exists());
-
-    Host.getHost(0).getVM(0).invoke(
-        new SerializableRunnable("LocalProcessLauncherDUnitTest#testExistingPidFileThrows") {
-          @Override
-          public void run() {
-            try {
-              new LocalProcessLauncher(new File(absolutePath), false);
-              fail("Two processes both succeeded in creating " + pidFile);
-            } catch (FileAlreadyExistsException e) {
-              // passed
-            } catch (IllegalStateException e) {
-              throw new AssertionError(e);
-            } catch (IOException e) {
-              throw new AssertionError(e);
-            } catch (PidUnavailableException e) {
-              throw new AssertionError(e);
-            }
-          }
-        });
-  }
-
-  @Test
-  public void testForceReplacesExistingPidFile() throws Exception {
-    final File pidFile = new File(
-        getClass().getSimpleName() + File.separator + "testForceReplacesExistingPidFile.pid");
-    final String absolutePath = pidFile.getAbsolutePath();
-
-    assertFalse(pidFile.exists());
-    final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
-    assertTrue(pidFile.exists());
-    assertNotNull(launcher);
-    final int pid = launcher.getPid();
-
-    Host.getHost(0).getVM(0).invoke(
-        new SerializableRunnable("LocalProcessLauncherDUnitTest#testForceReplacesExistingPidFile") {
-          @Override
-          public void run() {
-            try {
-              final LocalProcessLauncher launcher =
-                  new LocalProcessLauncher(new File(absolutePath), true);
-              assertNotSame(pid, launcher.getPid());
-              assertFalse(pid == launcher.getPid());
-
-              final FileReader fr = new FileReader(absolutePath);
-              final BufferedReader br = new BufferedReader(fr);
-              final int pidFromFile = Integer.parseInt(br.readLine());
-              br.close();
-
-              assertNotSame(pid, pidFromFile);
-              assertFalse(pid == pidFromFile);
-              assertEquals(launcher.getPid(), pidFromFile);
-            } catch (IllegalStateException e) {
-              throw new AssertionError(e);
-            } catch (IOException e) {
-              throw new AssertionError(e);
-            } catch (FileAlreadyExistsException e) {
-              throw new AssertionError(e);
-            } catch (PidUnavailableException e) {
-              throw new AssertionError(e);
-            }
-          }
-        });
-  }
-
-  @Test
-  public void testPidFileReadByOtherProcess() throws Exception {
-    final File pidFile =
-        new File(getClass().getSimpleName() + File.separator + "testPidFileReadByOtherProcess.pid");
-    final String absolutePath = pidFile.getAbsolutePath();
-
-    assertFalse(pidFile.exists());
-    final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
-    assertTrue(pidFile.exists());
-    assertNotNull(launcher);
-    final int pid = launcher.getPid();
-
-    Host.getHost(0).getVM(0).invoke(
-        new SerializableRunnable("LocalProcessLauncherDUnitTest#testPidFileReadByOtherProcess") {
-          @Override
-          public void run() {
-            try {
-              final FileReader fr = new FileReader(absolutePath);
-              final BufferedReader br = new BufferedReader(fr);
-              final int pidFromFile = Integer.parseInt(br.readLine());
-              br.close();
-              assertEquals(pid, pidFromFile);
-            } catch (FileNotFoundException e) {
-              throw new Error(e);
-            } catch (IOException e) {
-              throw new Error(e);
-            }
-          }
-        });
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java
new file mode 100755
index 0000000..deefa41
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.apache.geode.test.dunit.Host.getHost;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.io.IntegerFileReader;
+import org.apache.geode.test.dunit.DistributedTestCase;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
+import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
+
+/**
+ * Two-process functional tests for {@link LocalProcessLauncher}.
+ * 
+ * @since GemFire 7.0
+ */
+@Category(DistributedTest.class)
+public class LocalProcessLauncherDistributedTest extends DistributedTestCase {
+
+  private int pid;
+  private File pidFile;
+  private VM otherVM;
+
+  @Rule
+  public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
+
+  @Rule
+  public SerializableTestName testName = new SerializableTestName();
+
+  @Before
+  public void before() throws Exception {
+    pid = identifyPid();
+    pidFile = new File(temporaryFolder.getRoot(), testName.getMethodName() + ".pid");
+    otherVM = getHost(0).getVM(0);
+  }
+
+  @Test
+  public void existingPidFileThrowsFileAlreadyExistsException() throws Exception {
+    // arrange
+    otherVM.invoke(this::createPidFile);
+    int firstPid = new IntegerFileReader(pidFile).readFromFile();
+
+    // act/assert
+    assertThatThrownBy(() -> new LocalProcessLauncher(pidFile, false))
+        .isInstanceOf(FileAlreadyExistsException.class);
+    assertThat(new IntegerFileReader(pidFile).readFromFile()).isEqualTo(firstPid);
+  }
+
+  @Test
+  public void forceReplacesExistingPidFile() throws Exception {
+    // arrange
+    otherVM.invoke(this::createPidFile);
+    int firstPid = new IntegerFileReader(pidFile).readFromFile();
+
+    // act
+    new LocalProcessLauncher(pidFile, true);
+
+    // assert
+    int secondPid = new IntegerFileReader(pidFile).readFromFile();
+    assertThat(secondPid).isNotEqualTo(firstPid).isEqualTo(pid);
+  }
+
+  private void createPidFile()
+      throws FileAlreadyExistsException, IOException, PidUnavailableException {
+    new LocalProcessLauncher(pidFile, false);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java
new file mode 100644
index 0000000..2bcdeb3
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.LocalProcessLauncher.PROPERTY_IGNORE_IS_PID_ALIVE;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.internal.process.io.IntegerFileWriter;
+import org.apache.geode.internal.process.lang.AvailablePid;
+import org.apache.geode.test.junit.Retry;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.apache.geode.test.junit.rules.RetryRule;
+
+/**
+ * Functional integration tests for {@link LocalProcessLauncher}.
+ *
+ * <p>
+ * Tests involving fakePid use {@link RetryRule} because the fakePid may become used by a real
+ * process before the test executes.
+ */
+@Category(IntegrationTest.class)
+public class LocalProcessLauncherIntegrationTest {
+
+  private static final int PREFERRED_FAKE_PID = 42;
+
+  private File pidFile;
+  private int actualPid;
+  private int fakePid;
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+  @Rule
+  public RetryRule retryRule = new RetryRule();
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Before
+  public void before() throws Exception {
+    pidFile = new File(temporaryFolder.getRoot(), "my.pid");
+    actualPid = identifyPid();
+    fakePid = new AvailablePid().findAvailablePid(PREFERRED_FAKE_PID);
+
+    assertThat(pidFile).doesNotExist();
+  }
+
+  @Test
+  public void createsPidFile() throws Exception {
+    // act
+    new LocalProcessLauncher(pidFile, false);
+
+    // assert
+    assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+  }
+
+  @Test
+  @Retry(3)
+  public void existingPidFileThrowsFileAlreadyExistsException() throws Exception {
+    // arrange
+    System.setProperty(PROPERTY_IGNORE_IS_PID_ALIVE, "true");
+    new IntegerFileWriter(pidFile).writeToFile(fakePid);
+
+    // act/assert
+    assertThatThrownBy(() -> new LocalProcessLauncher(pidFile, false))
+        .isInstanceOf(FileAlreadyExistsException.class);
+  }
+
+  @Test
+  public void overwritesPidFileIfForce() throws Exception {
+    // arrange
+    new IntegerFileWriter(pidFile).writeToFile(actualPid);
+
+    // act
+    new LocalProcessLauncher(pidFile, true);
+
+    // assert
+    assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+  }
+
+  @Test
+  @Retry(3)
+  public void overwritesPidFileIfOtherPidIsNotAlive() throws Exception {
+    // arrange
+    new IntegerFileWriter(pidFile).writeToFile(fakePid);
+
+    // act
+    new LocalProcessLauncher(pidFile, false);
+
+    // assert
+    assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+  }
+
+  @Test
+  public void overwritesEmptyPidFile() throws Exception {
+    // arrange
+    new EmptyFileWriter(pidFile).createNewFile();
+
+    // act
+    new LocalProcessLauncher(pidFile, false);
+
+    // assert
+    assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+  }
+
+  @Test
+  public void getPidReturnsActualPid() throws Exception {
+    // arrange
+    LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
+
+    // act/assert
+    assertThat(launcher.getPid()).isEqualTo(actualPid);
+  }
+
+  @Test
+  public void getPidFileReturnsPidFile() throws Exception {
+    // arrange
+    LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
+
+    // act/assert
+    assertThat(launcher.getPidFile()).isEqualTo(pidFile);
+  }
+
+  @Test
+  public void closeDeletesPidFile() throws Exception {
+    // arrange
+    LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
+    assertThat(pidFile).exists();
+
+    // act
+    launcher.close();
+
+    // assert
+    assertThat(pidFile).doesNotExist();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java
deleted file mode 100755
index 9393949..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestName;
-
-import org.apache.geode.internal.OSProcess;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * Unit tests for ProcessLauncher.
- * 
- * @since GemFire 7.0
- */
-@Category(IntegrationTest.class)
-public class LocalProcessLauncherJUnitTest {
-
-  @Rule
-  public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
-  @Rule
-  public TestName testName = new TestName();
-
-  private File pidFile;
-
-  @Before
-  public void setUp() throws Exception {
-    this.pidFile = new File(this.temporaryFolder.getRoot(), testName.getMethodName() + ".pid");
-  }
-
-  @Test
-  public void testPidAccuracy() throws PidUnavailableException {
-    int pid = ProcessUtils.identifyPid();
-    assertTrue(pid > 0);
-    int osProcessPid = OSProcess.getId();
-    if (osProcessPid > 0) {
-      assertEquals(OSProcess.getId(), pid);
-    } else {
-      // not much to test if OSProcess native code is unusable
-    }
-  }
-
-  @Test
-  public void testPidFileIsCreated() throws Exception {
-    assertFalse(pidFile.exists());
-    new LocalProcessLauncher(pidFile, false);
-    assertTrue(pidFile.exists());
-  }
-
-  @Test
-  public void testPidFileContainsPid() throws Exception {
-    final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
-    assertNotNull(launcher);
-    assertTrue(pidFile.exists());
-
-    final FileReader fr = new FileReader(pidFile);
-    final BufferedReader br = new BufferedReader(fr);
-    final int pid = Integer.parseInt(br.readLine());
-    br.close();
-
-    assertTrue(pid > 0);
-    assertEquals(launcher.getPid(), pid);
-    assertEquals(ProcessUtils.identifyPid(), pid);
-  }
-
-  @Test
-  public void testPidFileIsCleanedUp() throws Exception {
-    final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
-    assertTrue(pidFile.exists());
-    launcher.close(); // TODO: launch an external JVM and then close it nicely
-    assertFalse(pidFile.exists());
-  }
-
-  @Test
-  public void testExistingPidFileThrows() throws Exception {
-    assertTrue(pidFile.createNewFile());
-    assertTrue(pidFile.exists());
-
-    final FileWriter writer = new FileWriter(pidFile);
-    // use a read pid that exists
-    writer.write(String.valueOf(ProcessUtils.identifyPid()));
-    writer.close();
-
-    try {
-      new LocalProcessLauncher(pidFile, false);
-      fail("LocalProcessLauncher should have thrown FileAlreadyExistsException");
-    } catch (FileAlreadyExistsException e) {
-      // passed
-    }
-  }
-
-  @Test
-  public void testStalePidFileIsReplaced() throws Exception {
-    assertTrue(pidFile.createNewFile());
-    assertTrue(pidFile.exists());
-
-    final FileWriter writer = new FileWriter(pidFile);
-    writer.write(String.valueOf(Integer.MAX_VALUE));
-    writer.close();
-
-    try {
-      new LocalProcessLauncher(pidFile, false);
-    } catch (FileAlreadyExistsException e) {
-      fail("LocalProcessLauncher should not have thrown FileAlreadyExistsException");
-    }
-
-    final FileReader fr = new FileReader(pidFile);
-    final BufferedReader br = new BufferedReader(fr);
-    final int pid = Integer.parseInt(br.readLine());
-    br.close();
-
-    assertTrue(pid > 0);
-    assertEquals(ProcessUtils.identifyPid(), pid);
-  }
-
-  @Test
-  public void testForceReplacesExistingPidFile() throws Exception {
-    assertTrue("testForceReplacesExistingPidFile is broken if PID == Integer.MAX_VALUE",
-        ProcessUtils.identifyPid() != Integer.MAX_VALUE);
-
-    assertTrue(pidFile.createNewFile());
-    assertTrue(pidFile.exists());
-
-    final FileWriter writer = new FileWriter(pidFile);
-    writer.write(String.valueOf(Integer.MAX_VALUE));
-    writer.close();
-
-    try {
-      new LocalProcessLauncher(pidFile, true);
-    } catch (FileAlreadyExistsException e) {
-      fail("LocalProcessLauncher should not have thrown FileAlreadyExistsException");
-    }
-
-    final FileReader fr = new FileReader(pidFile);
-    final BufferedReader br = new BufferedReader(fr);
-    final int pid = Integer.parseInt(br.readLine());
-    br.close();
-
-    assertTrue(pid > 0);
-    assertEquals(ProcessUtils.identifyPid(), pid);
-  }
-
-  @Test
-  public void testPidUnavailableThrows() {
-    final String name = "Name without PID";
-    try {
-      ProcessUtils.identifyPid(name);
-      fail("PidUnavailableException should have been thrown for " + name);
-    } catch (PidUnavailableException e) {
-      // passed
-    }
-  }
-}


[10/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java
new file mode 100644
index 0000000..000318c
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.internal.util.StopWatch;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for {@link NativeProcessUtils}.
+ */
+@Category(IntegrationTest.class)
+public class NativeProcessUtilsIntegrationTest {
+
+  /** Max sleep timeout for {@link ProcessSleeps} */
+  private static final int PROCESS_TIMEOUT_MILLIS = 10 * 60 * 1000;
+
+  private static final String FILE_NAME = "pid.txt";
+
+  private NativeProcessUtils nativeProcessUtils;
+  private Process process;
+  private File pidFile;
+  private int pid;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Before
+  public void before() throws Exception {
+    File directory = temporaryFolder.getRoot();
+
+    List<String> command = new ArrayList<>();
+    command
+        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
+    command.add("-cp");
+    command.add(System.getProperty("java.class.path"));
+    command.add(ProcessSleeps.class.getName());
+
+    process = new ProcessBuilder(command).directory(directory).start();
+    assertThat(process.isAlive()).isTrue();
+
+    pidFile = new File(directory, FILE_NAME);
+    await().atMost(2, MINUTES).until(() -> assertThat(pidFile).exists());
+
+    pid = new PidFile(pidFile).readPid();
+    assertThat(pid).isGreaterThan(0);
+
+    nativeProcessUtils = new NativeProcessUtils();
+  }
+
+  @After
+  public void after() throws Exception {
+    process.destroyForcibly();
+  }
+
+  @Test
+  public void killProcessKillsOtherProcess() throws Exception {
+    // act
+    nativeProcessUtils.killProcess(pid);
+
+    // assert
+    await().atMost(2, MINUTES).until(() -> assertThat(process.isAlive()).isFalse());
+  }
+
+  @Test
+  public void isProcessAliveReturnsTrueForLiveProcess() throws Exception {
+    // act/assert
+    assertThat(nativeProcessUtils.isProcessAlive(pid)).isTrue();
+  }
+
+  @Test
+  public void isProcessAliveReturnsFalseForDeadProcess() throws Exception {
+    // arrange
+    process.destroyForcibly();
+
+    // act/assert
+    await().atMost(2, MINUTES).until(() -> assertThat(process.isAlive()).isFalse());
+    assertThat(nativeProcessUtils.isProcessAlive(pid)).isFalse();
+  }
+
+  /**
+   * Class with main that uses LocalProcessLauncher to create a PidFile and then sleeps.
+   */
+  protected static class ProcessSleeps {
+    public static void main(final String... args) throws Exception {
+      new LocalProcessLauncher(new File(FILE_NAME), false);
+      StopWatch stopWatch = new StopWatch(true);
+      while (stopWatch.elapsedTimeMillis() < PROCESS_TIMEOUT_MILLIS) {
+        Thread.sleep(1000);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java
new file mode 100644
index 0000000..9c845b8
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.lang.AvailablePid;
+import org.apache.geode.test.junit.Retry;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.apache.geode.test.junit.rules.RetryRule;
+
+/**
+ * Unit tests for {@link NativeProcessUtils}.
+ *
+ * <p>
+ * Tests involving fakePid use {@link RetryRule} because the fakePid may become used by a real
+ * process before the test executes.
+ */
+@Category(UnitTest.class)
+public class NativeProcessUtilsTest {
+
+  private static final int PREFERRED_FAKE_PID = 42;
+
+  private int actualPid;
+  private int fakePid;
+  private NativeProcessUtils nativeProcessUtils;
+
+  @Rule
+  public RetryRule retryRule = new RetryRule();
+
+  @Before
+  public void before() throws Exception {
+    actualPid = identifyPid();
+    fakePid = new AvailablePid().findAvailablePid(PREFERRED_FAKE_PID);
+    nativeProcessUtils = new NativeProcessUtils();
+  }
+
+  @Test
+  public void isAttachApiAvailable_returnsFalse() throws Exception {
+    assertThat(nativeProcessUtils.isAttachApiAvailable()).isFalse();
+  }
+
+  @Test
+  public void isAvailable_returnsTrue() throws Exception {
+    assertThat(nativeProcessUtils.isAvailable()).isTrue();
+  }
+
+  @Test
+  public void isProcessAlive_livePid_returnsTrue() throws Exception {
+    assertThat(nativeProcessUtils.isProcessAlive(actualPid)).isTrue();
+  }
+
+  @Test
+  @Retry(3)
+  public void isProcessAlive_deadPid_returnsFalse() throws Exception {
+    assertThat(nativeProcessUtils.isProcessAlive(fakePid)).isFalse();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java
new file mode 100755
index 0000000..05b7cbc
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessStreamReader.ReadingMode.NON_BLOCKING;
+
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for NonBlockingProcessStreamReader which was introduced to fix TRAC
+ * #51967: "GFSH start hangs on Windows"
+ *
+ * @see BlockingProcessStreamReaderIntegrationTest
+ * @see BlockingProcessStreamReaderWindowsTest
+ *
+ * @since GemFire 8.2
+ */
+@Category(IntegrationTest.class)
+public class NonBlockingProcessStreamReaderIntegrationTest
+    extends BaseProcessStreamReaderIntegrationTest {
+
+  /**
+   * This test hangs on Windows if the implementation is blocking instead of non-blocking. Geode
+   * will always use the non-blocking implementation on Windows. If someone accidentally changes
+   * this, then the probably the first thing you'll notice is this test hanging.
+   */
+  @Test
+  public void canCloseStreamsWhileProcessIsAlive() throws Exception {
+    // arrange
+    givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+    // act
+    process.getOutputStream().close();
+    process.getErrorStream().close();
+    process.getInputStream().close();
+
+    // assert
+    assertThatProcessIsAlive(process);
+  }
+
+  @Test
+  public void canStopReadersWhileProcessIsAlive() throws Exception {
+    // arrange
+    givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+    // act
+    stdout.stop();
+    stderr.stop();
+
+    // assert
+    assertThatProcessIsAlive(process);
+  }
+
+  @Test
+  public void capturesStdoutWhileProcessIsAlive() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessPrintsToStdout.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStopped();
+    assertThatStdOutContainsExactly(ProcessPrintsToStdout.STDOUT);
+    assertThatStdErrContainsExactly(ProcessPrintsToStdout.STDERR);
+  }
+
+  @Test
+  public void capturesStderrWhileProcessIsAlive() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessPrintsToStderr.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStopped();
+    assertThatStdOutContainsExactly(ProcessPrintsToStderr.STDOUT);
+    assertThatStdErrContainsExactly(ProcessPrintsToStderr.STDERR);
+  }
+
+  @Test
+  public void capturesBothWhileProcessIsAlive() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessPrintsToBoth.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStopped();
+    assertThatStdOutContainsExactly(ProcessPrintsToBoth.STDOUT);
+    assertThatStdErrContainsExactly(ProcessPrintsToBoth.STDERR);
+  }
+
+  @Test
+  public void capturesStderrWhenProcessFailsDuringStart() throws Exception {
+    // arrange
+    givenStartedProcessWithStreamListeners(ProcessThrowsError.class);
+
+    // act
+    waitUntilProcessStops();
+
+    // assert
+    assertThatProcessAndReadersStoppedWithExitValue(1);
+    assertThatStdOutContainsExactly(ProcessThrowsError.STDOUT);
+    assertThatStdErrContains(ProcessThrowsError.ERROR_MSG);
+  }
+
+  @Override
+  protected ReadingMode getReadingMode() {
+    return NON_BLOCKING;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java
deleted file mode 100755
index 105e7f0..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.util.concurrent.Callable;
-
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
-import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * Tests NonBlockingProcessStreamReader which was introduced to fix TRAC bug #51967.
- * 
- * None of the tests should be skipped or hang on Windows.
- * 
- * @since GemFire 8.2
- */
-@Category(IntegrationTest.class)
-public class NonBlockingProcessStreamReaderJUnitTest extends ProcessStreamReaderTestCase {
-
-  @Test
-  public void canCloseStreamsWhileProcessIsAlive() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
-    this.stderr = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    assertIsAlive(this.process);
-
-    assertEventuallyIsRunning(this.stderr);
-    assertEventuallyIsRunning(this.stdout);
-
-    this.process.getErrorStream().close();
-    this.process.getOutputStream().close();
-    this.process.getInputStream().close();
-
-    this.stderr.stop();
-    this.stdout.stop();
-
-    assertIsAlive(this.process);
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void canStopReadersWhileProcessIsAlive() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
-    this.stderr = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    assertIsAlive(this.process);
-
-    assertEventuallyIsRunning(this.stderr);
-    assertEventuallyIsRunning(this.stdout);
-
-    this.stderr.stop();
-    this.stdout.stop();
-
-    this.process.getErrorStream().close();
-    this.process.getOutputStream().close();
-    this.process.getInputStream().close();
-
-    assertIsAlive(this.process);
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesStdoutWhileProcessIsAlive() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStdout.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    assertEquals("", stderrBuffer.toString());
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-    StringBuilder sb = new StringBuilder().append(ProcessPrintsToStdout.LINES[0])
-        .append(ProcessPrintsToStdout.LINES[1]).append(ProcessPrintsToStdout.LINES[2]);
-    assertEquals(sb.toString(), stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesStderrWhileProcessIsAlive() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStderr.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    StringBuilder sb = new StringBuilder().append(ProcessPrintsToStderr.LINES[0])
-        .append(ProcessPrintsToStderr.LINES[1]).append(ProcessPrintsToStderr.LINES[2]);
-    assertEquals(sb.toString(), stderrBuffer.toString());
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-    assertEquals("", stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesBothWhileProcessIsAlive() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToBoth.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    StringBuilder sb = new StringBuilder().append(ProcessPrintsToBoth.ERR_LINES[0])
-        .append(ProcessPrintsToBoth.ERR_LINES[1]).append(ProcessPrintsToBoth.ERR_LINES[2]);
-    assertEquals(sb.toString(), stderrBuffer.toString());
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-    sb = new StringBuilder().append(ProcessPrintsToBoth.OUT_LINES[0])
-        .append(ProcessPrintsToBoth.OUT_LINES[1]).append(ProcessPrintsToBoth.OUT_LINES[2]);
-    assertEquals(sb.toString(), stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-
-  @Test
-  public void capturesStderrWhenProcessFailsDuringStart() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessThrowsError.class)).start();
-
-    final StringBuffer stderrBuffer = new StringBuffer();
-    InputListener stderrListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stderrBuffer.append(line);
-      }
-    };
-
-    final StringBuffer stdoutBuffer = new StringBuffer();
-    InputListener stdoutListener = new InputListener() {
-      @Override
-      public void notifyInputLine(String line) {
-        stdoutBuffer.append(line);
-      }
-    };
-
-    this.stderr =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stdout =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
-    this.stderr.start();
-    this.stdout.start();
-
-    // wait for process to die
-    assertEventuallyFalse("Process never died", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return ProcessUtils.isProcessAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
-    final int exitValue = this.process.exitValue();
-    assertNotEquals(0, exitValue);
-
-    this.stderr.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stderr.isRunning());
-
-    this.stdout.join(READER_JOIN_TIMEOUT);
-    assertFalse(this.stdout.isRunning());
-
-    // System.out.println("Stopping ProcessStreamReader");
-    this.stderr.stop();
-    this.stdout.stop();
-
-    // System.out.println("stderr=\n" + stderrBuffer.toString());
-    assertTrue(stderrBuffer.toString() + " does not contain " + ProcessThrowsError.ERROR_MSG,
-        stderrBuffer.toString().contains(ProcessThrowsError.ERROR_MSG));
-
-    // System.out.println("stdout=\n" + stdoutBuffer.toString());
-
-    // System.out.println("Closing streams");
-    this.process.getErrorStream().close();
-    this.process.getInputStream().close();
-
-    this.process.destroy();
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java
new file mode 100755
index 0000000..584f185
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.internal.process.io.IntegerFileWriter;
+import org.apache.geode.internal.process.lang.AvailablePid;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for {@link PidFile}.
+ * 
+ * @since GemFire 8.2
+ */
+@Category(IntegrationTest.class)
+public class PidFileIntegrationTest {
+
+  private File directory;
+  private File pidFile;
+  private String pidFileName;
+  private ExecutorService futures;
+  private int pid;
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Before
+  public void before() throws Exception {
+    directory = temporaryFolder.getRoot();
+    pidFile = new File(directory, "pid.txt");
+    pidFileName = pidFile.getName();
+    futures = Executors.newFixedThreadPool(2);
+    pid = identifyPid();
+  }
+
+  @After
+  public void after() {
+    assertThat(this.futures.shutdownNow()).isEmpty();
+  }
+
+  @Test
+  public void readsIntFromFile() throws Exception {
+    // arrange
+    String value = "42";
+    new IntegerFileWriter(pidFile).writeToFile(value);
+
+    // act
+    int readValue = new PidFile(pidFile).readPid();
+
+    // assert
+    assertThat(readValue).isEqualTo(Integer.parseInt(value));
+  }
+
+  @Test
+  public void readingEmptyFileThrowsIllegalArgumentException() throws Exception {
+    // arrange
+    new IntegerFileWriter(pidFile).writeToFile("");
+
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(pidFile).readPid())
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void readingFileWithNonIntegerThrowsIllegalArgumentException() throws Exception {
+    // arrange
+    String value = "forty two";
+    new IntegerFileWriter(pidFile).writeToFile(value);
+
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(pidFile).readPid())
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid pid '" + value + "' found");
+  }
+
+  @Test
+  public void readingFileWithNegativeIntegerThrowsIllegalArgumentException() throws Exception {
+    // arrange
+    String value = "-42";
+    new IntegerFileWriter(pidFile).writeToFile(value);
+
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(pidFile).readPid())
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid pid '" + value + "' found");
+  }
+
+  @Test
+  public void readingNullFileThrowsNullPointerException() throws Exception {
+    // arrange
+    pidFile = null;
+
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(pidFile).readPid())
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void findsCorrectFileByName() throws Exception {
+    // arrange
+    new IntegerFileWriter(pidFile).writeToFile(pid);
+    int[] pids = new AvailablePid().findAvailablePids(4);
+    for (int i = 1; i <= pids.length; i++) {
+      new IntegerFileWriter(new File(directory, "pid" + i + ".txt")).writeToFile(pids[i - 1]);
+    }
+    assertThat(directory.listFiles()).hasSize(pids.length + 1);
+
+    // act
+    PidFile namedPidFile = new PidFile(directory, pidFile.getName());
+
+    // assert
+    assertThat(namedPidFile.getFile()).hasContent(String.valueOf(pid));
+    assertThat(namedPidFile.readPid()).isEqualTo(pid);
+  }
+
+  @Test
+  public void missingFileInEmptyDirectoryThrowsFileNotFoundException() throws Exception {
+    // arrange
+    assertThat(pidFile).doesNotExist();
+
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(directory, pidFileName).readPid())
+        .isInstanceOf(FileNotFoundException.class).hasMessage(
+            "Unable to find PID file '" + pidFileName + "' in directory '" + directory + "'");
+  }
+
+  @Test
+  public void fileForDirectoryThrowsIllegalArgumentException() throws Exception {
+    // arrange
+    File directoryIsFile = temporaryFolder.newFile("my.file");
+
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(directoryIsFile, pidFileName).readPid())
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Nonexistent directory '" + directoryIsFile + "' specified");
+  }
+
+  @Test
+  public void missingFileThrowsFileNotFoundException() throws Exception {
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(pidFile).readPid())
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Nonexistent file '" + pidFile + "' specified");
+  }
+
+  @Test
+  public void missingFileInFullDirectoryThrowsFileNotFoundException() throws Exception {
+    // arrange
+    int[] pids = new AvailablePid().findAvailablePids(4);
+    for (int i = 1; i <= pids.length; i++) {
+      new IntegerFileWriter(new File(directory, "pid" + i + ".txt")).writeToFile(pids[i - 1]);
+    }
+    assertThat(directory.listFiles()).hasSameSizeAs(pids);
+
+    // act/assert
+    assertThatThrownBy(() -> new PidFile(directory, pidFileName).readPid())
+        .isInstanceOf(FileNotFoundException.class).hasMessage(
+            "Unable to find PID file '" + pidFileName + "' in directory '" + directory + "'");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java
deleted file mode 100755
index 0ca73c4..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.jmock.Mockery;
-import org.jmock.lib.concurrent.Synchroniser;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.ExpectedException;
-import org.junit.rules.TemporaryFolder;
-
-import org.apache.geode.internal.util.StopWatch;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.apache.geode.test.junit.rules.ExpectedTimeoutRule;
-
-/**
- * Unit tests the PidFile class.
- * 
- * @since GemFire 8.2
- */
-@Category(IntegrationTest.class)
-public class PidFileJUnitTest {
-
-  @Rule
-  public TemporaryFolder testFolder = new TemporaryFolder();
-
-  @Rule
-  public ExpectedException thrown = ExpectedException.none();
-
-  @Rule
-  public ExpectedTimeoutRule timeout = ExpectedTimeoutRule.none();
-
-  protected Mockery mockContext;
-  private ExecutorService futures;
-
-  @Before
-  public void before() {
-    mockContext = new Mockery() {
-      {
-        setImposteriser(ClassImposteriser.INSTANCE);
-        setThreadingPolicy(new Synchroniser());
-      }
-    };
-    this.futures = Executors.newFixedThreadPool(2);
-  }
-
-  @After
-  public void after() {
-    mockContext.assertIsSatisfied();
-    assertTrue(this.futures.shutdownNow().isEmpty());
-  }
-
-  @Test
-  public void readsIntFromFile() throws Exception {
-    final File file = testFolder.newFile("my.pid");
-    final String value = "42";
-    writeToFile(file, value);
-
-    final int readValue = new PidFile(file).readPid();
-    assertEquals(Integer.parseInt(value), readValue);
-  }
-
-  @Test
-  public void readingEmptyFileThrowsIllegalArgumentException() throws Exception {
-    final File file = testFolder.newFile("my.pid");
-
-    thrown.expect(IllegalArgumentException.class);
-    thrown.expectMessage("Invalid pid 'null' found");
-
-    new PidFile(file).readPid();
-  }
-
-  @Test
-  public void readingFileWithNonIntegerThrowsIllegalArgumentException() throws Exception {
-    final File file = testFolder.newFile("my.pid");
-    final String value = "fortytwo";
-    writeToFile(file, value);
-
-    thrown.expect(IllegalArgumentException.class);
-    thrown.expectMessage("Invalid pid '" + value + "' found");
-
-    new PidFile(file).readPid();
-  }
-
-  @Test
-  public void readingFileWithNegativeIntegerThrowsIllegalArgumentException() throws Exception {
-    final File file = testFolder.newFile("my.pid");
-    final String value = "-42";
-    writeToFile(file, value);
-
-    thrown.expect(IllegalArgumentException.class);
-    thrown.expectMessage("Invalid pid '" + value + "' found");
-
-    new PidFile(file).readPid();
-  }
-
-  @Test
-  public void readingNullFileThrowsNullPointerException() throws Exception {
-    final File file = null;
-
-    thrown.expect(NullPointerException.class);
-
-    new PidFile(file).readPid();
-  }
-
-  @Test
-  public void timesOutReadingFromEmptyFile() throws Exception {
-    final File file = testFolder.newFile("my.pid");
-
-    timeout.expect(TimeoutException.class);
-    timeout.expectMessage("Invalid pid 'null' found");
-    timeout.expectMinimumDuration(1000);
-    timeout.expectMaximumDuration(10000);
-    timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
-
-    new PidFile(file).readPid(1500, TimeUnit.MILLISECONDS);
-  }
-
-  @Test
-  public void readsIntBeforeTimeout() throws Exception {
-    final int AWAIT_LATCH_TIMEOUT_MILLIS = 10 * 1000;
-    final int OPEN_LATCH_DELAY_MILLIS = 2 * 1000;
-    final int FUTURE_GET_TIMEOUT_MILLIS = 2 * 1000;
-    final int READ_PID_TIMEOUT_MILLIS = 2 * OPEN_LATCH_DELAY_MILLIS;
-
-    final File file = testFolder.newFile("my.pid");
-    final FileWriter writer = new FileWriter(file);
-
-    final CountDownLatch writePidLatch = new CountDownLatch(1);
-    final String value = "42";
-
-    // start Future to write the pid later but before timeout
-    Future<Boolean> futureWritePid = this.futures.submit(new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        writePidLatch.await(AWAIT_LATCH_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
-        writeToFile(file, value);
-        return true;
-      }
-    });
-
-    // start Future to sleep and release the delay
-    Future<Boolean> futureOpenLatch = this.futures.submit(new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        Thread.sleep(OPEN_LATCH_DELAY_MILLIS);
-        writePidLatch.countDown();
-        return true;
-      }
-    });
-
-    StopWatch stopWatch = new StopWatch(true);
-    final int readValue = new PidFile(file).readPid(READ_PID_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
-    assertEquals(Integer.parseInt(value), readValue);
-
-    long duration = stopWatch.elapsedTimeMillis();
-    assertTrue(duration > OPEN_LATCH_DELAY_MILLIS);
-    assertTrue(duration < READ_PID_TIMEOUT_MILLIS);
-
-    assertEquals(0, writePidLatch.getCount());
-    assertTrue(futureOpenLatch.get(FUTURE_GET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
-    assertTrue(futureWritePid.get(FUTURE_GET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
-  }
-
-  @Test
-  public void findsCorrectFile() throws Exception {
-    final File directory = testFolder.getRoot();
-
-    final String fileNames[] = new String[] {"other.txt", "my.txt", "a.log", "b.log"};
-    for (String fileName : fileNames) {
-      testFolder.newFile(fileName);
-    }
-
-    final int pidValue = 42;
-    final File file = testFolder.newFile("my.pid");
-    writeToFile(file, String.valueOf(pidValue));
-
-    final File other = testFolder.newFile("other.pid");
-    writeToFile(other, "43");
-
-    final File[] files = directory.listFiles();
-    assertEquals(fileNames.length + 2, files.length);
-
-    PidFile pidFile = new PidFile(directory, file.getName());
-    assertEquals(file, pidFile.getFile());
-
-    int value = pidFile.readPid();
-    assertEquals(pidValue, value);
-  }
-
-  @Test
-  public void missingFileInEmptyDirectoryThrowsFileNotFoundException() throws Exception {
-    final File directory = testFolder.getRoot();
-
-    final String pidFileName = "my.pid";
-
-    thrown.expect(FileNotFoundException.class);
-    thrown.expectMessage("Unable to find PID file '" + pidFileName + "' in directory " + directory);
-
-    new PidFile(directory, pidFileName);
-  }
-
-  @Test
-  public void missingFileThrowsFileNotFoundException() throws Exception {
-    final String pidFileName = "my.pid";
-
-    final File directory = testFolder.getRoot();
-    final File file = new File(directory, pidFileName);
-
-    thrown.expect(FileNotFoundException.class);
-    thrown.expectMessage("Unable to find PID file '" + file + "'");
-
-    new PidFile(file);
-  }
-
-  @Test
-  public void missingFileInFullDirectoryThrowsFileNotFoundException() throws Exception {
-    final File directory = testFolder.getRoot();
-
-    final String fileNames[] = new String[] {"other.txt", "my.txt", "a.log", "b.log"};
-    for (String fileName : fileNames) {
-      testFolder.newFile(fileName);
-    }
-
-    final File other = testFolder.newFile("other.pid");
-    writeToFile(other, "43");
-
-    final File[] files = directory.listFiles();
-    assertEquals(fileNames.length + 1, files.length);
-
-    final String pidFileName = "my.pid";
-
-    thrown.expect(FileNotFoundException.class);
-    thrown.expectMessage("Unable to find PID file '" + pidFileName + "' in directory " + directory);
-
-    new PidFile(directory, pidFileName);
-  }
-
-  private void writeToFile(final File file, String value) throws IOException {
-    final FileWriter writer = new FileWriter(file);
-    writer.write(value);
-    writer.flush();
-    writer.close();
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java
new file mode 100644
index 0000000..aafa260
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.internal.process.io.IntegerFileWriter;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for {@link ProcessControllerFactory}.
+ */
+@Category(IntegrationTest.class)
+public class ProcessControllerFactoryIntegrationTest {
+
+  private ProcessControllerFactory factory;
+  private ProcessControllerParameters parameters;
+  private File directory;
+  private File pidFile;
+  private String pidFileName;
+  private int pid;
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Before
+  public void before() throws Exception {
+    factory = new ProcessControllerFactory();
+    parameters = mock(ProcessControllerParameters.class);
+    directory = temporaryFolder.getRoot();
+    pidFile = new File(directory, "pid.txt");
+    pidFileName = pidFile.getName();
+    pid = identifyPid();
+
+    assertThat(pidFile).doesNotExist();
+    assertThat(isProcessAlive(pid)).isTrue();
+  }
+
+  @Test
+  public void createProcessController_withoutPidFile_throwsFileNotFoundException()
+      throws Exception {
+    // act/assert
+    assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName))
+        .isInstanceOf(FileNotFoundException.class);
+  }
+
+  @Test
+  public void createProcessController_returnsMBeanProcessController() throws Exception {
+    // arrange
+    new IntegerFileWriter(pidFile).writeToFile(pid);
+
+    // act
+    ProcessController controller =
+        factory.createProcessController(parameters, directory, pidFileName);
+
+    // assert
+    assertThat(controller).isInstanceOf(MBeanProcessController.class);
+  }
+
+  @Test
+  public void createProcessController_withoutAttachAPI_returnsFileProcessController()
+      throws Exception {
+    // arrange
+    new IntegerFileWriter(pidFile).writeToFile(pid);
+    System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true");
+    factory = new ProcessControllerFactory();
+
+    // act
+    ProcessController controller =
+        factory.createProcessController(parameters, directory, pidFileName);
+
+    // assert
+    assertThat(controller).isInstanceOf(FileProcessController.class);
+  }
+
+  @Test
+  public void createProcessController_nullParameters_throwsNullPointerException() throws Exception {
+    // arrange
+    parameters = null;
+
+    // act/assert
+    assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void createProcessController_nullDirectory_throwsNullPointerException() throws Exception {
+    // arrange
+    directory = null;
+
+    // act/assert
+    assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+
+  @Test
+  public void createProcessController_nullPidFileName_throwsNullPointerException()
+      throws Exception {
+    // arrange
+    pidFileName = null;
+
+    // act/assert
+    assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName))
+        .isInstanceOf(IllegalArgumentException.class);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java
deleted file mode 100755
index b9c8030..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.io.File;
-
-import javax.management.ObjectName;
-
-import org.junit.After;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.test.junit.categories.UnitTest;
-
-/**
- * @since GemFire 8.0
- */
-@Category(UnitTest.class)
-public class ProcessControllerFactoryJUnitTest {
-
-  @After
-  public void tearDown() throws Exception {
-    enableAttachApi();
-  }
-
-  @Test
-  public void testIsAttachAPIFound() throws Exception {
-    validateProcessControllerFactory(true);
-    disableAttachApi();
-    validateProcessControllerFactory(false);
-    enableAttachApi();
-    validateProcessControllerFactory(true);
-  }
-
-  private void validateProcessControllerFactory(boolean isAttachAPIFound) throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertEquals(isAttachAPIFound, factory.isAttachAPIFound());
-    if (isAttachAPIFound) {
-      final ProcessControllerParameters parms = new NullMBeanControllerParameters();
-      final ProcessController controller =
-          factory.createProcessController(parms, ProcessUtils.identifyPid());
-      assertTrue(controller instanceof MBeanProcessController);
-    } else {
-      final ProcessControllerParameters parms = new NullFileControllerParameters();
-      final ProcessController controller =
-          factory.createProcessController(parms, ProcessUtils.identifyPid());
-      assertTrue(controller instanceof FileProcessController);
-    }
-  }
-
-  private static void disableAttachApi() {
-    System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true");
-  }
-
-  private static void enableAttachApi() {
-    System.clearProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API);
-  }
-
-  private static class NullMBeanControllerParameters implements ProcessControllerParameters {
-    @Override
-    public int getProcessId() {
-      return 0;
-    }
-
-    @Override
-    public ProcessType getProcessType() {
-      return null;
-    }
-
-    @Override
-    public ObjectName getNamePattern() {
-      return null;
-    }
-
-    @Override
-    public String getPidAttribute() {
-      return null;
-    }
-
-    @Override
-    public String getStatusMethod() {
-      return null;
-    }
-
-    @Override
-    public String getStopMethod() {
-      return null;
-    }
-
-    @Override
-    public String[] getAttributes() {
-      return null;
-    }
-
-    @Override
-    public Object[] getValues() {
-      return null;
-    }
-
-    @Override
-    public File getPidFile() {
-      throw new UnsupportedOperationException("Not implemented by NullMBeanControllerParameters");
-    }
-
-    @Override
-    public File getWorkingDirectory() {
-      throw new UnsupportedOperationException("Not implemented by NullMBeanControllerParameters");
-    }
-  }
-
-  private static class NullFileControllerParameters implements ProcessControllerParameters {
-    @Override
-    public int getProcessId() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public ProcessType getProcessType() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public ObjectName getNamePattern() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public String getPidAttribute() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public String getStatusMethod() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public String getStopMethod() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public String[] getAttributes() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public Object[] getValues() {
-      throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters");
-    }
-
-    @Override
-    public File getPidFile() {
-      return null;
-    }
-
-    @Override
-    public File getWorkingDirectory() {
-      return null;
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java
new file mode 100755
index 0000000..55f5d58
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link ProcessControllerFactory}.
+ *
+ * @since GemFire 8.0
+ */
+@Category(UnitTest.class)
+public class ProcessControllerFactoryTest {
+
+  private ProcessControllerFactory factory;
+  private ProcessControllerParameters parameters;
+  private int pid;
+
+  @Rule
+  public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+  @Before
+  public void before() throws Exception {
+    factory = new ProcessControllerFactory();
+    parameters = mock(ProcessControllerParameters.class);
+    pid = identifyPid();
+  }
+
+  @Test
+  public void isAttachAPIFound_withAttachAPI_returnsTrue() throws Exception {
+    // act/assert
+    assertThat(factory.isAttachAPIFound()).isTrue();
+  }
+
+  @Test
+  public void isAttachAPIFound_withoutAttachAPI_returnsFalse() throws Exception {
+    // arrange
+    System.setProperty(PROPERTY_DISABLE_ATTACH_API, "true");
+    factory = new ProcessControllerFactory();
+
+    // act/assert
+    assertThat(factory.isAttachAPIFound()).isFalse();
+  }
+
+  @Test
+  public void createProcessController_withAttachAPI_returnsMBeanProcessController()
+      throws Exception {
+    // act
+    ProcessController controller = factory.createProcessController(parameters, pid);
+
+    // assert
+    assertThat(controller).isInstanceOf(MBeanProcessController.class);
+  }
+
+  @Test
+  public void createProcessController_withoutAttachAPI_returnsFileProcessController()
+      throws Exception {
+    // arrange
+    System.setProperty(PROPERTY_DISABLE_ATTACH_API, "true");
+    factory = new ProcessControllerFactory();
+
+    // act
+    ProcessController controller = factory.createProcessController(parameters, pid);
+
+    // assert
+    assertThat(controller).isInstanceOf(FileProcessController.class);
+  }
+
+  @Test
+  public void createProcessController_withNullParameters_throwsNullPointerException()
+      throws Exception {
+    // arrange
+    parameters = null;
+
+    // act/assert
+    assertThatThrownBy(() -> factory.createProcessController(parameters, pid))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid parameters 'null' specified");
+  }
+
+  @Test
+  public void createProcessController_withZeroPid_throwsIllegalArgumentException()
+      throws Exception {
+    // arrange
+    pid = 0;
+
+    // act/assert
+    assertThatThrownBy(() -> factory.createProcessController(parameters, 0))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid pid '" + 0 + "' specified");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java
new file mode 100644
index 0000000..c98f026
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.Collections.synchronizedList;
+import static org.apache.geode.internal.process.ProcessLauncherContext.getOverriddenDefaults;
+import static org.apache.geode.internal.process.ProcessLauncherContext.getStartupListener;
+import static org.apache.geode.internal.process.ProcessLauncherContext.isRedirectingOutput;
+import static org.apache.geode.internal.process.ProcessLauncherContext.remove;
+import static org.apache.geode.internal.process.ProcessLauncherContext.set;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link ProcessLauncherContext}.
+ */
+@Category(UnitTest.class)
+public class ProcessLauncherContextTest {
+
+  private boolean redirectOutput;
+  private Properties overriddenDefaults;
+  private StartupStatusListener startupListener;
+  private List<String> statusMessageList;
+
+  @Before
+  public void before() throws Exception {
+    redirectOutput = false;
+    overriddenDefaults = new Properties();
+    startupListener = mock(StartupStatusListener.class);
+    statusMessageList = synchronizedList(new ArrayList<>());
+  }
+
+  @After
+  public void after() throws Exception {
+    remove();
+  }
+
+  @Test
+  public void isRedirectingOutput_defaultsToFalse() throws Exception {
+    assertThat(isRedirectingOutput()).isFalse();
+  }
+
+  @Test
+  public void getOverriddenDefaults_defaultsToEmpty() throws Exception {
+    assertThat(getOverriddenDefaults()).isEmpty();
+  }
+
+  @Test
+  public void getStartupListener_defaultsToNull() throws Exception {
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void null_overriddenDefaults_throwsIllegalArgumentException() throws Exception {
+    // arrange
+    overriddenDefaults = null;
+
+    // act/assert
+    assertThatThrownBy(() -> set(redirectOutput, overriddenDefaults, startupListener))
+        .isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Invalid overriddenDefaults 'null' specified");
+  }
+
+  @Test
+  public void null_startupListener_isAllowed() throws Exception {
+    // arrange
+    startupListener = null;
+
+    // act
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // assert
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void empty_overriddenDefaults_isAllowed() throws Exception {
+    // act
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // assert
+    assertThat(getOverriddenDefaults()).isEmpty();
+  }
+
+  @Test
+  public void isRedirectingOutput_returnsPassedValue() throws Exception {
+    // arrange
+    redirectOutput = true;
+
+    // act
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // assert
+    assertThat(isRedirectingOutput()).isTrue();
+  }
+
+  @Test
+  public void getOverriddenDefaults_returnsPassedInProps() throws Exception {
+    // arrange
+    overriddenDefaults.setProperty("key", "value");
+
+    // act
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // assert
+    assertThat(getOverriddenDefaults()).hasSize(1).containsEntry("key", "value");
+  }
+
+  @Test
+  public void getStartupListener_returnsPassedInListener() throws Exception {
+    // arrange
+    overriddenDefaults.setProperty("key", "value");
+
+    // act
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // assert
+    assertThat(getStartupListener()).isSameAs(startupListener);
+  }
+
+  @Test
+  public void remove_clearsOverriddenDefaults() throws Exception {
+    // arrange
+    overriddenDefaults.setProperty("key", "value");
+    set(false, overriddenDefaults, startupListener);
+
+    // act
+    remove();
+
+    // assert
+    assertThat(getOverriddenDefaults()).isEmpty();
+  }
+
+  @Test
+  public void remove_unsetsRedirectOutput() throws Exception {
+    // arrange
+    redirectOutput = true;
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // act
+    remove();
+
+    // assert
+    assertThat(isRedirectingOutput()).isFalse();
+  }
+
+  @Test
+  public void remove_clearsStartupListener() throws Exception {
+    // arrange
+    startupListener = statusMessage -> statusMessageList.add(statusMessage);
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // act
+    remove();
+
+    // assert
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void startupListener_installsInStartupStatus() throws Exception {
+    // arrange
+    startupListener = statusMessage -> statusMessageList.add(statusMessage);
+
+    // act
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // assert
+    assertThat(StartupStatus.getStartupListener()).isSameAs(startupListener);
+  }
+
+  @Test
+  public void remove_uninstallsInStartupStatus() throws Exception {
+    // arrange
+    startupListener = statusMessage -> statusMessageList.add(statusMessage);
+    set(redirectOutput, overriddenDefaults, startupListener);
+
+    // act
+    remove();
+
+    // assert
+    assertThat(StartupStatus.getStartupListener()).isNull();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java
deleted file mode 100755
index 32a7f79..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.Callable;
-
-import org.junit.After;
-import org.junit.Test;
-
-import org.apache.geode.internal.util.StopWatch;
-
-/**
- * Functional tests for ProcessStreamReader.
- * 
- */
-public abstract class ProcessStreamReaderTestCase {
-
-  /** Sleep timeout for {@link ProcessSleeps} instead of sleeping Long.MAX_VALUE */
-  protected static final int PROCESS_FAILSAFE_TIMEOUT = 10 * 60 * 1000;
-
-  /** Additional time for launched processes to live before terminating */
-  protected static final int PROCESS_TIME_TO_LIVE = 3 * 500;
-
-  /** Timeout to wait for a forked process to start */
-  protected static final int WAIT_FOR_PROCESS_TO_START_TIMEOUT = 60 * 1000;
-
-  /**
-   * Timeout to wait for a running process to die -- this keeps timing out so I'm increasing it very
-   * large
-   */
-  protected static final int WAIT_FOR_PROCESS_TO_DIE_TIMEOUT = 5 * 60 * 1000;
-
-  /** Timeout to wait for a new {@link ProcessStreamReader} to be running */
-  protected static final int WAIT_FOR_READER_IS_RUNNING_TIMEOUT = 20 * 1000;
-
-  /** Timeout to join to a running ProcessStreamReader thread */
-  protected static final int READER_JOIN_TIMEOUT = 20 * 1000;
-
-  /** Brief time to sleep before repeating a conditional check */
-  protected static final int INTERVAL = 20;
-
-  protected Process process;
-  protected ProcessStreamReader stderr;
-  protected ProcessStreamReader stdout;
-
-  @After
-  public void stopReadersAndDestroyProcess() throws Exception {
-    if (this.stderr != null) {
-      this.stderr.stop();
-    }
-    if (this.stdout != null) {
-      this.stdout.stop();
-    }
-    if (this.process != null) {
-      this.process.destroy(); // this is async and can require more than 10 seconds in Jenkins
-      /*
-       * assertEventuallyFalse("Timed out destroying process after " +
-       * WAIT_FOR_PROCESS_TO_DIE_TIMEOUT/(60*1000) + " minutes", new Callable<Boolean>() {
-       * 
-       * @Override public Boolean call() throws Exception { return isAlive(process); } },
-       * WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-       */
-    }
-  }
-
-  @Test
-  public void processLivesAfterClosingStreams() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-    this.process.getErrorStream().close();
-    this.process.getOutputStream().close();
-    this.process.getInputStream().close();
-    assertIsAlive(process);
-    this.process.destroy();
-  }
-
-  @Test
-  public void processTerminatesWhenDestroyed() throws Exception {
-    this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-    assertIsAlive(this.process);
-    this.process.destroy();
-    assertEventuallyFalse("Timed out destroying process", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return isAlive(process);
-      }
-    }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-    assertNotEquals(0, this.process.exitValue());
-  }
-
-  protected static void assertEventuallyTrue(final String message, final Callable<Boolean> callable,
-      final int timeout, final int interval) throws Exception {
-    boolean done = false;
-    for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done =
-        (callable.call())) {
-      Thread.sleep(interval);
-    }
-    assertTrue(message + " within timeout of " + timeout + " milliseconds", done);
-  }
-
-  protected static void assertEventuallyFalse(final String message,
-      final Callable<Boolean> callable, final int timeout, final int interval) throws Exception {
-    boolean done = false;
-    for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done =
-        (!callable.call())) {
-      Thread.sleep(interval);
-    }
-    assertTrue(message + " within timeout of " + timeout + " milliseconds", done);
-  }
-
-  protected static void assertIsAlive(final Process process) {
-    assertTrue(isAlive(process));
-  }
-
-  protected static void assertIsNotAlive(final Process process) {
-    assertFalse(isAlive(process));
-  }
-
-  protected static boolean isAlive(final Process process) {
-    try {
-      process.exitValue();
-      return false;
-    } catch (IllegalThreadStateException e) {
-      return true;
-    }
-  }
-
-  protected static String getJavaPath() {
-    String java = "java";
-    // if (SystemUtils.isWindows()) {
-    // java = "javaw";
-    // }
-    return new File(new File(System.getProperty("java.home"), "bin"), java).getPath();
-  }
-
-  protected static String getClassPath() {
-    return System.getProperty("java.class.path");
-  }
-
-  protected static String[] createCommandLine(final Class<?> clazz) {
-    return createCommandLine(clazz, null);
-  }
-
-  protected static String[] createCommandLine(final Class<?> clazz, final String[] jvmArgsOpts) {
-    List<String> commandLine = new ArrayList<>();
-
-    commandLine.add(getJavaPath());
-    commandLine.add("-server");
-    commandLine.add("-classpath");
-    commandLine.add(getClassPath());
-
-    addJvmArgumentsAndOptions(commandLine, jvmArgsOpts);
-
-    commandLine.add("-Djava.awt.headless=true");
-    commandLine.add(clazz.getName());
-
-    return commandLine.toArray(new String[commandLine.size()]);
-  }
-
-  protected static void addJvmArgumentsAndOptions(final List<String> commandLine,
-      final String[] jvmArgsOpts) {
-    if (jvmArgsOpts != null) {
-      commandLine.addAll(Arrays.asList(jvmArgsOpts));
-    }
-  }
-
-  protected static void assertEventuallyIsRunning(final ProcessStreamReader reader)
-      throws Exception {
-    assertEventuallyTrue("Waiting for ProcessStreamReader to be running", new Callable<Boolean>() {
-      @Override
-      public Boolean call() throws Exception {
-        return reader.isRunning();
-      }
-    }, WAIT_FOR_READER_IS_RUNNING_TIMEOUT, INTERVAL);
-  }
-
-  protected static class ProcessSleeps {
-    public static void main(String[] args) throws InterruptedException {
-      Thread.sleep(PROCESS_FAILSAFE_TIMEOUT);
-    }
-  }
-
-  protected static class ProcessThrowsError {
-    protected static String[] LINES = new String[] {"ProcessThrowsError is starting\n",
-        "ProcessThrowsError is sleeping\n", "ProcessThrowsError is throwing\n"};
-    protected static String ERROR_MSG = "ProcessThrowsError throws Error";
-
-    public static void main(String[] args) throws InterruptedException {
-      System.err.print(LINES[0]);
-      System.err.print(LINES[1]);
-      Thread.sleep(PROCESS_TIME_TO_LIVE);
-      System.err.print(LINES[2]);
-      throw new Error(ERROR_MSG);
-    }
-  }
-
-  protected static class ProcessPrintsToStdout {
-    protected static String[] LINES = new String[] {"ProcessPrintsToStdout is starting\n",
-        "ProcessPrintsToStdout is sleeping\n", "ProcessPrintsToStdout is exiting\n"};
-
-    public static void main(String[] args) throws InterruptedException {
-      System.out.print(LINES[0]);
-      System.out.print(LINES[1]);
-      Thread.sleep(PROCESS_TIME_TO_LIVE);
-      System.out.print(LINES[2]);
-    }
-  }
-
-  protected static class ProcessPrintsToStderr {
-    protected static String[] LINES = new String[] {"ProcessPrintsToStdout is starting\n",
-        "ProcessPrintsToStdout is sleeping\n", "ProcessPrintsToStdout is exiting\n"};
-
-    public static void main(String[] args) throws InterruptedException {
-      System.err.print(LINES[0]);
-      System.err.print(LINES[1]);
-      Thread.sleep(PROCESS_TIME_TO_LIVE);
-      System.err.print(LINES[2]);
-    }
-  }
-
-  protected static class ProcessPrintsToBoth {
-    protected static String[] OUT_LINES = new String[] {"ProcessPrintsToBoth(out) is starting\n",
-        "ProcessPrintsToBoth(out) is sleeping\n", "ProcessPrintsToBoth(out) is exiting\n"};
-    protected static String[] ERR_LINES = new String[] {"ProcessPrintsToBoth(err) is starting\n",
-        "ProcessPrintsToBoth(err) is sleeping\n", "ProcessPrintsToBoth(err) is exiting\n"};
-
-    public static void main(String[] args) throws InterruptedException {
-      System.out.print(OUT_LINES[0]);
-      System.err.print(ERR_LINES[0]);
-      System.out.print(OUT_LINES[1]);
-      System.err.print(ERR_LINES[1]);
-      Thread.sleep(PROCESS_TIME_TO_LIVE);
-      System.out.print(OUT_LINES[2]);
-      System.err.print(ERR_LINES[2]);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java
new file mode 100644
index 0000000..04e23f3
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.Collections.synchronizedList;
+import static org.apache.geode.internal.process.StartupStatus.clearListener;
+import static org.apache.geode.internal.process.StartupStatus.getStartupListener;
+import static org.apache.geode.internal.process.StartupStatus.setListener;
+import static org.apache.geode.internal.process.StartupStatus.startup;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.i18n.StringId;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class StartupStatusTest {
+
+  private StartupStatusListener listener;
+  private List<String> statusMessageList;
+
+  @Before
+  public void before() throws Exception {
+    listener = mock(StartupStatusListener.class);
+    statusMessageList = synchronizedList(new ArrayList<>());
+  }
+
+  @After
+  public void after() throws Exception {
+    clearListener();
+  }
+
+  @Test
+  public void getStartupListener_returnsNullByDefault() throws Exception {
+    // act/assert
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void setListener_null_clearsStartupListener() throws Exception {
+    // arrange
+    listener = null;
+
+    // act
+    setListener(listener);
+
+    // assert
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void getStartupListener_returnsSetListener() throws Exception {
+    // arrange
+    setListener(listener);
+
+    // act/assert
+    assertThat(getStartupListener()).isSameAs(listener);
+  }
+
+  @Test
+  public void clearListener_doesNothingIfNull() throws Exception {
+    // arrange
+    listener = null;
+    setListener(listener);
+    assertThat(getStartupListener()).isNull();
+
+    // act
+    clearListener();
+
+    // assert
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void clearListener_unsetsListener() throws Exception {
+    // arrange
+    setListener(listener);
+    assertThat(getStartupListener()).isNotNull();
+
+    // act
+    clearListener();
+
+    // assert
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void startup_nullStringId_throwsIllegalArgumentException() throws Exception {
+    // arrange
+    StringId stringId = null;
+    Object[] params = new Object[0];
+
+    // act/assert
+    assertThatThrownBy(() -> startup(stringId, params)).isInstanceOf(IllegalArgumentException.class)
+        .hasMessage("Invalid msgId 'null' specified");
+  }
+
+  @Test
+  public void startup_emptyParams() throws Exception {
+    // arrange
+    StringId stringId = new StringId(1, "my string");
+    Object[] params = new Object[0];
+
+    // act
+    startup(stringId, params);
+
+    // assert (does not throw)
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void startup_doesNothingIfNoListener() throws Exception {
+    // arrange
+    StringId stringId = new StringId(1, "my string");
+    Object[] params = new Object[0];
+
+    // act
+    startup(stringId, params);
+
+    // assert (does nothing)
+    assertThat(getStartupListener()).isNull();
+  }
+
+  @Test
+  public void startup_invokesListener() throws Exception {
+    // arrange
+    listener = statusMessage -> statusMessageList.add(statusMessage);
+    StringId stringId = new StringId(1, "my string");
+    Object[] params = new Object[0];
+    setListener(listener);
+
+    // act
+    startup(stringId, params);
+
+    // assert
+    assertThat(statusMessageList).hasSize(1).contains("my string");
+  }
+
+  @Test
+  public void startupTwice_invokesListenerTwice() throws Exception {
+    // arrange
+    listener = statusMessage -> statusMessageList.add(statusMessage);
+    StringId stringIdOne = new StringId(1, "my string");
+    StringId stringIdTwo = new StringId(2, "other string");
+    Object[] params = new Object[0];
+    setListener(listener);
+
+    // act
+    startup(stringIdOne, params);
+    startup(stringIdTwo, params);
+
+    // assert
+    assertThat(statusMessageList).hasSize(2).contains("my string").contains("other string");
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java
new file mode 100644
index 0000000..3acf0a6
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process.io;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Creates an empty file.
+ */
+public class EmptyFileWriter {
+
+  private final File file;
+
+  public EmptyFileWriter(final File file) {
+    this.file = file;
+  }
+
+  public File createNewFile() throws IOException {
+    assertThat(file).doesNotExist();
+    assertThat(file.createNewFile()).isTrue();
+    assertThat(file).exists();
+    return file;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java
new file mode 100644
index 0000000..4f405bf
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process.io;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+public class IntegerFileReader {
+
+  private final File file;
+
+  public IntegerFileReader(final File file) {
+    this.file = file;
+  }
+
+  public int readFromFile() throws IOException {
+    assertThat(file).exists();
+    try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) {
+      return Integer.parseInt(bufferedReader.readLine());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java
new file mode 100644
index 0000000..47f54bc
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process.io;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Writes an integer to the file.
+ */
+public class IntegerFileWriter extends StringFileWriter {
+
+  public IntegerFileWriter(final File file) {
+    super(file);
+  }
+
+  public void writeToFile(final int pid) throws IOException {
+    writeToFile(String.valueOf(pid));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java
new file mode 100644
index 0000000..76db475
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process.io;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * Writes a string to the file.
+ */
+public class StringFileWriter {
+
+  private final File file;
+
+  public StringFileWriter(final File file) {
+    this.file = file;
+  }
+
+  public void writeToFile(final String string) throws IOException {
+    assertThat(file).doesNotExist();
+    try (FileWriter writer = new FileWriter(file)) {
+      writer.write(string);
+      writer.flush();
+    }
+    assertThat(file).exists();
+  }
+
+}


[16/23] geode git commit: GEODE-3413: overhaul launcher and process classes and tests

Posted by zh...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTest.java
index 47e512a..cc42a53 100755
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTest.java
@@ -14,1043 +14,251 @@
  */
 package org.apache.geode.distributed;
 
-import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.apache.geode.distributed.AbstractLauncher.Status.NOT_RESPONDING;
+import static org.apache.geode.distributed.AbstractLauncher.Status.ONLINE;
+import static org.apache.geode.distributed.AbstractLauncher.Status.STOPPED;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.PrintStream;
-import java.lang.management.ManagementFactory;
+import java.net.BindException;
 import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
 
-import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
 
-import org.apache.geode.distributed.AbstractLauncher.Status;
 import org.apache.geode.distributed.LocatorLauncher.Builder;
 import org.apache.geode.distributed.LocatorLauncher.LocatorState;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.internal.AvailablePort;
-import org.apache.geode.internal.DistributionLocator;
-import org.apache.geode.internal.ExitCode;
 import org.apache.geode.internal.GemFireVersion;
-import org.apache.geode.internal.logging.InternalLogWriter;
-import org.apache.geode.internal.logging.LocalLogWriter;
-import org.apache.geode.internal.net.SocketCreatorFactory;
 import org.apache.geode.internal.process.ProcessControllerFactory;
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
-import org.apache.geode.test.junit.categories.FlakyTest;
 import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
 
 /**
- * Integration tests for launching a Locator in a forked process.
+ * Integration tests for using {@code LocatorLauncher} as an application main in a forked JVM.
  *
  * @since GemFire 8.0
  */
 @Category(IntegrationTest.class)
-@RunWith(Parameterized.class)
-@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
-public class LocatorLauncherRemoteIntegrationTest
-    extends AbstractLocatorLauncherRemoteIntegrationTestCase {
-
-  protected volatile Process process;
-  protected volatile ProcessStreamReader processOutReader;
-  protected volatile ProcessStreamReader processErrReader;
+public class LocatorLauncherRemoteIntegrationTest extends LocatorLauncherRemoteIntegrationTestCase {
 
   @Before
-  public final void setUpLocatorLauncherRemoteTest() throws Exception {}
-
-  @After
-  public final void tearDownLocatorLauncherRemoteTest() throws Exception {
-    if (this.process != null) {
-      this.process.destroy();
-      this.process = null;
-    }
-    if (this.processOutReader != null && this.processOutReader.isRunning()) {
-      this.processOutReader.stop();
-    }
-    if (this.processErrReader != null && this.processErrReader.isRunning()) {
-      this.processErrReader.stop();
-    }
+  public void setUpLocatorLauncherRemoteIntegrationTest() throws Exception {
+    assertThat(new ProcessControllerFactory().isAttachAPIFound()).isTrue();
   }
 
   @Test
-  public void testIsAttachAPIFound() throws Exception {
-    final ProcessControllerFactory factory = new ProcessControllerFactory();
-    assertTrue(factory.isAttachAPIFound());
-  }
+  public void startCreatesPidFile() throws Exception {
+    startLocator();
 
-  @Test
-  @Ignore("TRAC bug #52304: test is broken and needs to be reworked")
-  public void testRunningLocatorOutlivesForkingProcess()
-      throws Exception {}/*
-                          * // TODO: fix up this test
-                          * 
-                          * this.temporaryFolder.getRoot() = new File(getUniqueName());
-                          * this.temporaryFolder.getRoot().mkdir();
-                          * assertTrue(this.temporaryFolder.getRoot().isDirectory() &&
-                          * this.temporaryFolder.getRoot().canWrite());
-                          * 
-                          * // launch LocatorLauncherForkingProcess which then launches the GemFire
-                          * Locator final List<String> jvmArguments = getJvmArguments();
-                          * 
-                          * final List<String> command = new ArrayList<String>(); command.add(new
-                          * File(new File(System.getProperty("java.home"), "bin"),
-                          * "java").getCanonicalPath()); for (String jvmArgument : jvmArguments) {
-                          * command.add(jvmArgument); } command.add("-cp");
-                          * command.add(System.getProperty("java.class.path"));
-                          * command.add(LocatorLauncherRemoteDUnitTest.class.getName().concat("$").
-                          * concat(LocatorLauncherForkingProcess.class.getSimpleName()));
-                          * command.add(String.valueOf(this.locatorPort));
-                          * 
-                          * this.process = new
-                          * ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start(
-                          * ); this.processOutReader = new
-                          * ProcessStreamReader.Builder(this.process).inputStream(this.process.
-                          * getInputStream()).build().start(); this.processErrReader = new
-                          * ProcessStreamReader.Builder(this.process).inputStream(this.process.
-                          * getErrorStream()).build().start();
-                          * 
-                          * Thread waiting = new Thread(new Runnable() { public void run() { try {
-                          * assertIndexDetailsEquals(0, process.waitFor()); } catch
-                          * (InterruptedException ignore) {
-                          * logger.error("Interrupted while waiting for process!", ignore); } } });
-                          * 
-                          * try { waiting.start(); waiting.join(TIMEOUT_MILLISECONDS);
-                          * assertFalse("Process took too long and timed out!", waiting.isAlive());
-                          * } finally { if (waiting.isAlive()) { waiting.interrupt(); } }
-                          * 
-                          * LocatorLauncher locatorLauncher = new
-                          * Builder().setWorkingDirectory(this.temporaryFolder.getRoot().
-                          * getCanonicalPath()).build();
-                          * 
-                          * assertIndexDetailsEquals(Status.ONLINE,
-                          * locatorLauncher.status().getStatus());
-                          * assertIndexDetailsEquals(Status.STOPPED,
-                          * locatorLauncher.stop().getStatus()); }
-                          */
+    assertThat(getPidFile()).exists();
+  }
 
-  @Category(FlakyTest.class) // GEODE-473: random ports, BindException, forks JVM, uses
-                             // ErrorCollector
   @Test
-  public void testStartCreatesPidFile() throws Throwable {
-    // build and start the locator
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
+  public void pidFileContainsServerPid() throws Exception {
+    startLocator();
 
-    int pid = 0;
-    this.launcher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // check the status
-      final LocatorState locatorState = this.launcher.status();
-      assertNotNull(locatorState);
-      assertEquals(Status.ONLINE, locatorState.getStatus());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThatPidIsAlive(getLocatorPid());
   }
 
-  @Category(FlakyTest.class) // GEODE-530: BindException, random ports
   @Test
-  public void testStartDeletesStaleControlFiles() throws Throwable {
-    // create existing control files
-    this.stopRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getStopRequestFileName());
-    this.stopRequestFile.createNewFile();
-    assertTrue(this.stopRequestFile.exists());
-
-    this.statusRequestFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getStatusRequestFileName());
-    this.statusRequestFile.createNewFile();
-    assertTrue(this.statusRequestFile.exists());
-
-    this.statusFile =
-        new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getStatusFileName());
-    this.statusFile.createNewFile();
-    assertTrue(this.statusFile.exists());
+  public void startCreatesLogFile() throws Exception {
+    startLocator();
 
-    // build and start the locator
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for locator to start
-    int pid = 0;
-    this.launcher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate stale control files were deleted
-      waitForFileToDelete(this.stopRequestFile);
-      waitForFileToDelete(this.statusRequestFile);
-      waitForFileToDelete(this.statusFile);
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThat(getLogFile()).exists();
   }
 
-  @Category(FlakyTest.class) // GEODE-1229: BindException
   @Test
-  public void testStartOverwritesStalePidFile() throws Throwable {
-    // create existing pid file
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-    writePid(this.pidFile, Integer.MAX_VALUE);
-
-    // build and start the locator
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    int pid = 0;
-    this.launcher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertFalse(pid == Integer.MAX_VALUE);
+  public void startDeletesStaleControlFiles() throws Exception {
+    File stopRequestFile = givenControlFile(getStopRequestFileName());
+    File statusRequestFile = givenControlFile(getStatusRequestFileName());
+    File statusFile = givenControlFile(getStatusFileName());
 
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    startLocator();
 
-    // stop the locator
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertDeletionOf(stopRequestFile);
+    assertDeletionOf(statusRequestFile);
+    assertDeletionOf(statusFile);
   }
 
-  @Category(FlakyTest.class) // GEODE-764: BindException
+  /**
+   * This test takes > 1 minute to run in {@link LocatorLauncherRemoteFileIntegrationTest}.
+   */
   @Test
-  public void testStartUsingForceOverwritesExistingPidFile() throws Throwable {
-    // create existing pid file
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-    final int otherPid = getPid();
-    assertTrue("Pid " + otherPid + " should be alive", ProcessUtils.isProcessAlive(otherPid));
-    writePid(this.pidFile, otherPid);
-
-    // build and start the locator
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-    command.add("--force");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for locator to start
-    int pid = 0;
-    this.launcher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(this.launcher);
+  public void startOverwritesStalePidFile() throws Exception {
+    givenPidFile(fakePid);
 
-      // validate the pid file and its contents
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-      assertTrue(pid != otherPid);
+    startLocator();
 
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      assertEquals(Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThat(getLocatorPid()).isNotEqualTo(fakePid);
   }
 
+  /**
+   * This test takes > 1 minute to run in {@link LocatorLauncherRemoteFileIntegrationTest}.
+   */
   @Test
-  public void testStartUsingPortInUseFails() throws Throwable {
-    this.socket = SocketCreatorFactory
-        .createNonDefaultInstance(false, false, null, null, System.getProperties())
-        .createServerSocket(this.locatorPort, 50, null, -1);
-    this.locatorPort = this.socket.getLocalPort();
-
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--redirect-output");
-    command.add("--port=" + this.locatorPort);
-
-    String expectedString = "java.net.BindException";
-    AtomicBoolean outputContainedExpectedString = new AtomicBoolean();
+  public void startWithForceOverwritesExistingPidFile() throws Exception {
+    givenPidFile(localPid);
 
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).inputListener(createExpectedListener("sysout",
-            getUniqueName() + "#sysout", expectedString, outputContainedExpectedString))
-        .build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).inputListener(createExpectedListener("syserr",
-            getUniqueName() + "#syserr", expectedString, outputContainedExpectedString))
-        .build().start();
+    startLocator(withForce());
 
-    // wait for locator to start and fail
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      int code = process.waitFor();
-      assertEquals("Expected exit code 1 but was " + code, 1, code);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // check the status
-      final LocatorState locatorState = dirLauncher.status();
-      assertNotNull(locatorState);
-      assertEquals(Status.NOT_RESPONDING, locatorState.getStatus());
-
-      final String logFileName = getUniqueName() + ".log";
-      assertFalse("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // if the following fails, then the SHORTER_TIMEOUT is too short for slow machines
-    // or this test needs to use MainLauncher in ProcessWrapper
-
-    // validate that output contained BindException
-    this.errorCollector.checkThat(outputContainedExpectedString.get(), is(equalTo(true)));
-
-    // just in case the launcher started...
-    LocatorState status = null;
-    try {
-      status = dirLauncher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
-
-    this.errorCollector.checkThat(status.getStatus(),
-        is(equalTo(getExpectedStopStatusForNotRunning())));
+    assertThatPidIsAlive(getLocatorPid());
+    assertThat(getLocatorPid()).isNotEqualTo(localPid);
   }
 
   @Test
-  public void testStartWithDefaultPortInUseFails() throws Throwable {
-    String expectedString = "java.net.BindException";
-    AtomicBoolean outputContainedExpectedString = new AtomicBoolean();
-
-    this.socket = SocketCreatorFactory
-        .createNonDefaultInstance(false, false, null, null, System.getProperties())
-        .createServerSocket(this.locatorPort, 50, null, -1);
-    this.locatorPort = this.socket.getLocalPort();
-
-    assertFalse(AvailablePort.isPortAvailable(this.locatorPort, AvailablePort.SOCKET));
-    assertTrue(this.socket.isBound());
-    assertFalse(this.socket.isClosed());
-
-    // launch locator
-    final List<String> jvmArguments = getJvmArguments();
-    jvmArguments.add(
-        "-D" + DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY + "=" + this.locatorPort);
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).inputListener(createExpectedListener("sysout",
-            getUniqueName() + "#sysout", expectedString, outputContainedExpectedString))
-        .build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).inputListener(createExpectedListener("syserr",
-            getUniqueName() + "#syserr", expectedString, outputContainedExpectedString))
-        .build().start();
-
-    // wait for locator to start up
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      int code = process.waitFor(); // TODO: create flavor with timeout in ProcessUtils
-      assertEquals("Expected exit code 1 but was " + code, 1, code);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void startWithLocatorPortInUseFailsWithBindException() throws Exception {
+    givenLocatorPortInUse(nonDefaultLocatorPort);
 
-    try {
-      // check the status
-      final LocatorState locatorState = dirLauncher.status();
-      assertNotNull(locatorState);
-      assertEquals(Status.NOT_RESPONDING, locatorState.getStatus());
+    startLocatorShouldFail(withPort(nonDefaultLocatorPort));
 
-      // creation of log file seems to be random -- look into why sometime
-      final String logFileName = getUniqueName() + ".log";
-      assertFalse("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // if the following fails, then the SHORTER_TIMEOUT might be too short for slow machines
-    // or this test needs to use MainLauncher in ProcessWrapper
+    assertThatProcessIsNotAlive(getLocatorProcess());
+    assertThatLocatorThrew(BindException.class);
+  }
 
-    // validate that output contained BindException
-    this.errorCollector.checkThat(outputContainedExpectedString.get(), is(equalTo(true)));
+  @Test
+  public void startWithDefaultPortInUseFailsWithBindException() throws Exception {
+    givenLocatorPortInUse(defaultLocatorPort);
 
-    // just in case the launcher started...
-    LocatorState status = null;
-    try {
-      status = dirLauncher.stop();
-    } catch (Throwable t) {
-      // ignore
-    }
+    startLocatorShouldFail();
 
-    this.errorCollector.checkThat(status.getStatus(),
-        is(equalTo(getExpectedStopStatusForNotRunning())));
+    assertThatProcessIsNotAlive(getLocatorProcess());
+    assertThatLocatorThrew(BindException.class);
   }
 
   @Test
-  @Ignore("Need to rewrite this without using dunit.Host")
-  public void testStartWithExistingPidFileFails()
-      throws Throwable {}/*
-                          * this.temporaryFolder.getRoot() = new File(getUniqueName());
-                          * this.temporaryFolder.getRoot().mkdir();
-                          * assertTrue(this.temporaryFolder.getRoot().isDirectory() &&
-                          * this.temporaryFolder.getRoot().canWrite());
-                          * 
-                          * // create existing pid file this.pidFile = new
-                          * File(this.temporaryFolder.getRoot(),
-                          * ProcessType.LOCATOR.getPidFileName()); final int realPid =
-                          * Host.getHost(0).getVM(3).invoke(() -> ProcessUtils.identifyPid());
-                          * assertFalse("Remote pid shouldn't be the same as local pid " + realPid,
-                          * realPid == ProcessUtils.identifyPid()); writePid(this.pidFile, realPid);
-                          * 
-                          * // build and start the locator final List<String> jvmArguments =
-                          * getJvmArguments();
-                          * 
-                          * final List<String> command = new ArrayList<String>(); command.add(new
-                          * File(new File(System.getProperty("java.home"), "bin"),
-                          * "java").getCanonicalPath()); for (String jvmArgument : jvmArguments) {
-                          * command.add(jvmArgument); } command.add("-cp");
-                          * command.add(System.getProperty("java.class.path"));
-                          * command.add(LocatorLauncher.class.getName());
-                          * command.add(LocatorLauncher.Command.START.getName());
-                          * command.add(getUniqueName()); command.add("--port=" + this.locatorPort);
-                          * command.add("--redirect-output");
-                          * 
-                          * this.process = new
-                          * ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start(
-                          * ); this.processOutReader = new
-                          * ProcessStreamReader.Builder(this.process).inputStream(this.process.
-                          * getInputStream()).build().start(); this.processErrReader = new
-                          * ProcessStreamReader.Builder(this.process).inputStream(this.process.
-                          * getErrorStream()).build().start();
-                          * 
-                          * // collect and throw the FIRST failure Throwable failure = null;
-                          * 
-                          * final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-                          * .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath())
-                          * .build(); try { waitForLocatorToStart(dirLauncher, 10*1000, false); }
-                          * catch (Throwable e) { logger.error(e); if (failure == null) { failure =
-                          * e; } }
-                          * 
-                          * try { // check the status final LocatorState locatorState =
-                          * dirLauncher.status(); assertNotNull(locatorState);
-                          * assertIndexDetailsEquals(Status.NOT_RESPONDING,
-                          * locatorState.getStatus());
-                          * 
-                          * final String logFileName = getUniqueName()+".log";
-                          * assertFalse("Log file should not exist: " + logFileName, new
-                          * File(this.temporaryFolder.getRoot(), logFileName).exists());
-                          * 
-                          * } catch (Throwable e) { logger.error(e); if (failure == null) { failure
-                          * = e; } }
-                          * 
-                          * // just in case the launcher started... try { final LocatorState status
-                          * = dirLauncher.stop(); final Status theStatus = status.getStatus();
-                          * assertFalse(theStatus == Status.STARTING); assertFalse(theStatus ==
-                          * Status.ONLINE); } catch (Throwable e) { logger.error(e); if (failure ==
-                          * null) { failure = e; } }
-                          * 
-                          * if (failure != null) { throw failure; } } //
-                          * testStartWithExistingPidFileFails
-                          */
+  public void statusWithPidReturnsOnlineWithDetails() throws Exception {
+    givenRunningLocator();
+
+    LocatorState locatorState = new Builder().setPid(getLocatorPid()).build().status();
+
+    assertThat(locatorState.getStatus()).isEqualTo(ONLINE);
+    assertThat(locatorState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(locatorState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(locatorState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(locatorState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(locatorState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(locatorState.getLogFile()).isEqualTo(getLogFile().getCanonicalPath());
+    assertThat(locatorState.getMemberName()).isEqualTo(getUniqueName());
+    assertThat(locatorState.getPid().intValue()).isEqualTo(getLocatorPid());
+    assertThat(locatorState.getUptime()).isGreaterThan(0);
+    assertThat(locatorState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
+  }
 
   @Test
-  public void testStatusUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for locator to start
-    int pid = 0;
-    LocatorLauncher pidLauncher = null;
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(dirLauncher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
-
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      // validate the status
-      final LocatorState actualStatus = pidLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath(),
-          actualStatus.getWorkingDirectory());
-      assertEquals(jvmArguments, actualStatus.getJvmArguments());
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath() + File.separator
-          + getUniqueName() + ".log", actualStatus.getLogFile());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      if (pidLauncher == null) {
-        assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-      } else {
-        assertEquals(Status.STOPPED, pidLauncher.stop().getStatus());
-      }
-      waitForPidToStop(pid);
-      waitForFileToDelete(this.pidFile);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+  public void statusWithWorkingDirectoryReturnsOnlineWithDetails() throws Exception {
+    givenRunningLocator();
+
+    LocatorState locatorState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(locatorState.getStatus()).isEqualTo(ONLINE);
+    assertThat(locatorState.getClasspath()).isEqualTo(getClassPath());
+    assertThat(locatorState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(locatorState.getHost()).isEqualTo(InetAddress.getLocalHost().getCanonicalHostName());
+    assertThat(locatorState.getJavaVersion()).isEqualTo(System.getProperty("java.version"));
+    assertThat(locatorState.getJvmArguments()).isEqualTo(getJvmArguments());
+    assertThat(locatorState.getLogFile()).isEqualTo(getLogFile().getCanonicalPath());
+    assertThat(locatorState.getMemberName()).isEqualTo(getUniqueName());
+    assertThat(locatorState.getPid().intValue()).isEqualTo(readPidFile());
+    assertThat(locatorState.getUptime()).isGreaterThan(0);
+    assertThat(locatorState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
-  @Category(FlakyTest.class) // GEODE-569: BindException, random ports
   @Test
-  public void testStatusUsingWorkingDirectory() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for locator to start
-    int pid = 0;
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(dirLauncher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
+  public void statusWithEmptyPidFileThrowsIllegalArgumentException() throws Exception {
+    givenEmptyPidFile();
 
-      assertNotNull(dirLauncher);
-      assertFalse(dirLauncher.isRunning());
+    LocatorLauncher launcher = new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build();
 
-      // validate the status
-      final LocatorState actualStatus = dirLauncher.status();
-      assertNotNull(actualStatus);
-      assertEquals(Status.ONLINE, actualStatus.getStatus());
-      assertEquals(pid, actualStatus.getPid().intValue());
-      assertTrue(actualStatus.getUptime() > 0);
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath(),
-          actualStatus.getWorkingDirectory());
-      assertEquals(jvmArguments, actualStatus.getJvmArguments());
-      assertEquals(ManagementFactory.getRuntimeMXBean().getClassPath(),
-          actualStatus.getClasspath());
-      assertEquals(GemFireVersion.getGemFireVersion(), actualStatus.getGemFireVersion());
-      assertEquals(System.getProperty("java.version"), actualStatus.getJavaVersion());
-      assertEquals(this.temporaryFolder.getRoot().getCanonicalPath() + File.separator
-          + getUniqueName() + ".log", actualStatus.getLogFile());
-      assertEquals(InetAddress.getLocalHost().getCanonicalHostName(), actualStatus.getHost());
-      assertEquals(getUniqueName(), actualStatus.getMemberName());
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThatThrownBy(() -> launcher.status()).isInstanceOf(IllegalArgumentException.class)
+        .hasMessageContaining("Invalid pid 'null' found in");
   }
 
   @Test
-  public void testStatusWithEmptyPidFile() throws Exception {
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-    assertTrue(this.pidFile + " already exists", this.pidFile.createNewFile());
-
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    final LocatorState actualStatus = dirLauncher.status();
-    assertThat(actualStatus, is(notNullValue()));
-    assertThat(actualStatus.getStatus(), is(equalTo(Status.NOT_RESPONDING)));
-    assertThat(actualStatus.getPid(), is(nullValue()));
-    assertThat(actualStatus.getUptime().intValue(), is(equalTo(0)));
-    assertThat(actualStatus.getWorkingDirectory(),
-        is(equalTo(this.temporaryFolder.getRoot().getCanonicalPath())));
-    assertThat(actualStatus.getClasspath(), is(nullValue()));
-    assertThat(actualStatus.getGemFireVersion(), is(equalTo(GemFireVersion.getGemFireVersion())));
-    assertThat(actualStatus.getJavaVersion(), is(nullValue()));
-    assertThat(actualStatus.getLogFile(), is(nullValue()));
-    assertThat(actualStatus.getHost(), is(nullValue()));
-    assertThat(actualStatus.getMemberName(), is(nullValue()));
+  public void statusWithEmptyWorkingDirectoryReturnsNotRespondingWithDetails() throws Exception {
+    givenEmptyWorkingDirectory();
+
+    LocatorState locatorState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
+
+    assertThat(locatorState.getStatus()).isEqualTo(NOT_RESPONDING);
+    assertThat(locatorState.getClasspath()).isNull();
+    assertThat(locatorState.getGemFireVersion()).isEqualTo(GemFireVersion.getGemFireVersion());
+    assertThat(locatorState.getHost()).isNull();
+    assertThat(locatorState.getJavaVersion()).isNull();
+    assertThat(locatorState.getLogFile()).isNull();
+    assertThat(locatorState.getMemberName()).isNull();
+    assertThat(locatorState.getPid()).isNull();
+    assertThat(locatorState.getUptime().intValue()).isEqualTo(0);
+    assertThat(locatorState.getWorkingDirectory()).isEqualTo(getWorkingDirectoryPath());
   }
 
+  /**
+   * This test takes > 1 minute to run in {@link LocatorLauncherRemoteFileIntegrationTest}.
+   */
   @Test
-  public void testStatusWithNoPidFile() throws Exception {
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    LocatorState locatorState = dirLauncher.status();
-    assertEquals(Status.NOT_RESPONDING, locatorState.getStatus());
-  }
+  public void statusWithStalePidFileReturnsNotResponding() throws Exception {
+    givenPidFile(fakePid);
 
-  @Test
-  public void testStatusWithStalePidFile() throws Exception {
-    this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-    final int pid = 0;
-    assertFalse(ProcessUtils.isProcessAlive(pid));
-    writePid(this.pidFile, pid);
+    LocatorState locatorState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().status();
 
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    final LocatorState actualStatus = dirLauncher.status();
-    assertThat(actualStatus, is(notNullValue()));
-    assertThat(actualStatus.getStatus(), is(equalTo(Status.NOT_RESPONDING)));
-    assertThat(actualStatus.getPid(), is(nullValue()));
-    assertThat(actualStatus.getUptime().intValue(), is(equalTo(0)));
-    assertThat(actualStatus.getWorkingDirectory(),
-        is(equalTo(this.temporaryFolder.getRoot().getCanonicalPath())));
-    assertThat(actualStatus.getClasspath(), is(nullValue()));
-    assertThat(actualStatus.getGemFireVersion(), is(equalTo(GemFireVersion.getGemFireVersion())));
-    assertThat(actualStatus.getJavaVersion(), is(nullValue()));
-    assertThat(actualStatus.getLogFile(), is(nullValue()));
-    assertThat(actualStatus.getHost(), is(nullValue()));
-    assertThat(actualStatus.getMemberName(), is(nullValue()));
+    assertThat(locatorState.getStatus()).isEqualTo(NOT_RESPONDING);
   }
 
   @Test
-  public void testStopUsingPid() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
+  public void stopWithPidReturnsStopped() throws Exception {
+    givenRunningLocator();
 
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
+    LocatorState serverState = new Builder().setPid(getLocatorPid()).build().stop();
 
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(createLoggingListener("sysout", getUniqueName() + "#sysout")).build()
-            .start();
-    this.processErrReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(createLoggingListener("syserr", getUniqueName() + "#syserr")).build()
-            .start();
-
-    // wait for locator to start
-    int pid = 0;
-    LocatorLauncher pidLauncher = null;
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(dirLauncher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // use launcher with pid
-      pidLauncher = new Builder().setPid(pid).build();
-
-      assertNotNull(pidLauncher);
-      assertFalse(pidLauncher.isRunning());
-
-      // validate the status
-      final LocatorState status = pidLauncher.status();
-      assertNotNull(status);
-      assertEquals(Status.ONLINE, status.getStatus());
-      assertEquals(pid, status.getPid().intValue());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    // stop the locator
-    try {
-      if (pidLauncher == null) {
-        assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-      } else {
-        assertEquals(Status.STOPPED, pidLauncher.stop().getStatus());
-      }
-      waitForPidToStop(pid);
-      waitForFileToDelete(pidFile);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThat(serverState.getStatus()).isEqualTo(STOPPED);
   }
 
-  @Category(FlakyTest.class) // GEODE-847: random ports, BindException, forks JVM, uses
-                             // ErrorCollector
   @Test
-  public void testStopUsingWorkingDirectory() throws Throwable {
-    final List<String> jvmArguments = getJvmArguments();
-
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(this.temporaryFolder.getRoot()).start();
-    this.processOutReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getInputStream()).build().start();
-    this.processErrReader = new ProcessStreamReader.Builder(this.process)
-        .inputStream(this.process.getErrorStream()).build().start();
-
-    // wait for locator to start
-    int pid = 0;
-    final LocatorLauncher dirLauncher = new LocatorLauncher.Builder()
-        .setWorkingDirectory(this.temporaryFolder.getRoot().getCanonicalPath()).build();
-    try {
-      waitForLocatorToStart(dirLauncher);
+  public void stopWithPidStopsLocatorProcess() throws Exception {
+    givenRunningLocator();
 
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
+    new Builder().setPid(getLocatorPid()).build().stop();
 
-      // validate log file was created
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
-
-    try {
-      // stop the locator
-      assertEquals(Status.STOPPED, dirLauncher.stop().getStatus());
-      waitForPidToStop(pid);
-      assertFalse("PID file still exists!", this.pidFile.exists());
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertStopOf(getLocatorProcess());
   }
 
-  /**
-   * Used only by
-   * {@link LocatorLauncherRemoteIntegrationTest#testRunningLocatorOutlivesForkingProcess}
-   */
-  public static class LocatorLauncherForkingProcess {
+  @Test
+  public void stopWithPidDeletesPidFile() throws Exception {
+    givenRunningLocator();
 
-    public static void main(final String... args) throws FileNotFoundException {
-      File file = new File(System.getProperty("user.dir"),
-          LocatorLauncherForkingProcess.class.getSimpleName().concat(".log"));
+    new Builder().setPid(getLocatorPid()).build().stop();
 
-      LocalLogWriter logWriter = new LocalLogWriter(InternalLogWriter.ALL_LEVEL,
-          new PrintStream(new FileOutputStream(file, true)));
+    assertDeletionOf(getPidFile());
+  }
 
-      try {
-        final int port = Integer.parseInt(args[0]);
+  @Test
+  public void stopWithWorkingDirectoryReturnsStopped() throws Exception {
+    givenRunningLocator();
 
-        // launch LocatorLauncher
-        List<String> command = new ArrayList<String>();
-        command.add(
-            new File(new File(System.getProperty("java.home"), "bin"), "java").getAbsolutePath());
-        command.add("-cp");
-        command.add(System.getProperty("java.class.path"));
-        command.add("-D" + DistributionConfig.GEMFIRE_PREFIX + MCAST_PORT + "=0");
-        command.add(LocatorLauncher.class.getName());
-        command.add(LocatorLauncher.Command.START.getName());
-        command.add(LocatorLauncherForkingProcess.class.getSimpleName() + "_Locator");
-        command.add("--port=" + port);
-        command.add("--redirect-output");
+    LocatorState serverState =
+        new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
 
-        logWriter.info(
-            LocatorLauncherForkingProcess.class.getSimpleName() + "#main command: " + command);
-        logWriter.info(LocatorLauncherForkingProcess.class.getSimpleName() + "#main starting...");
+    assertThat(serverState.getStatus()).isEqualTo(STOPPED);
+  }
 
-        Process forkedProcess = new ProcessBuilder(command).start();
+  @Test
+  public void stopWithWorkingDirectoryStopsLocatorProcess() throws Exception {
+    givenRunningLocator();
 
-        @SuppressWarnings("unused")
-        ProcessStreamReader processOutReader = new ProcessStreamReader.Builder(forkedProcess)
-            .inputStream(forkedProcess.getInputStream()).build().start();
-        @SuppressWarnings("unused")
-        ProcessStreamReader processErrReader = new ProcessStreamReader.Builder(forkedProcess)
-            .inputStream(forkedProcess.getErrorStream()).build().start();
+    new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
 
-        logWriter.info(LocatorLauncherForkingProcess.class.getSimpleName()
-            + "#main waiting for locator to start...");
+    assertStopOf(getLocatorProcess());
+  }
 
-        waitForLocatorToStart(port, TIMEOUT_MILLISECONDS, 10, true);
+  @Test
+  public void stopWithWorkingDirectoryDeletesPidFile() throws Exception {
+    givenRunningLocator();
 
-        logWriter.info(LocatorLauncherForkingProcess.class.getSimpleName() + "#main exiting...");
+    new Builder().setWorkingDirectory(getWorkingDirectoryPath()).build().stop();
 
-        ExitCode.NORMAL.doSystemExit();
-      } catch (Throwable t) {
-        logWriter.info(LocatorLauncherForkingProcess.class.getSimpleName() + "#main error: " + t,
-            t);
-        System.exit(-1);
-      }
-    }
+    assertDeletionOf(getPidFile());
   }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTestCase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTestCase.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTestCase.java
new file mode 100644
index 0000000..b74eccc
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteIntegrationTestCase.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.distributed;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.internal.DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY;
+import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.BindException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.After;
+import org.junit.Before;
+
+import org.apache.geode.distributed.AbstractLauncher.Status;
+import org.apache.geode.distributed.LocatorLauncher.Builder;
+import org.apache.geode.distributed.LocatorLauncher.Command;
+import org.apache.geode.distributed.internal.DistributionConfig;
+import org.apache.geode.internal.process.ProcessStreamReader;
+import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
+
+/**
+ * Abstract base class for integration tests of {@link LocatorLauncher} as an application main in a
+ * forked JVM.
+ *
+ * @since GemFire 8.0
+ */
+public abstract class LocatorLauncherRemoteIntegrationTestCase
+    extends LocatorLauncherIntegrationTestCase implements UsesLocatorCommand {
+
+  private final AtomicBoolean threwBindException = new AtomicBoolean();
+
+  private volatile Process process;
+  private volatile ProcessStreamReader processOutReader;
+  private volatile ProcessStreamReader processErrReader;
+
+  private LocatorCommand locatorCommand;
+
+  @Before
+  public void setUp() throws Exception {
+    locatorCommand = new LocatorCommand(this);
+  }
+
+  @After
+  public void tearDownAbstractLocatorLauncherRemoteIntegrationTestCase() throws Exception {
+    if (process != null) {
+      process.destroy();
+    }
+    if (processOutReader != null && processOutReader.isRunning()) {
+      processOutReader.stop();
+    }
+    if (processErrReader != null && processErrReader.isRunning()) {
+      processErrReader.stop();
+    }
+  }
+
+  @Override
+  public List<String> getJvmArguments() {
+    List<String> jvmArguments = new ArrayList<>();
+    jvmArguments.add("-D" + DistributionConfig.GEMFIRE_PREFIX + "log-level=config");
+    jvmArguments
+        .add("-D" + TEST_OVERRIDE_DEFAULT_PORT_PROPERTY + "=" + String.valueOf(defaultLocatorPort));
+    return jvmArguments;
+  }
+
+  @Override
+  public String getName() {
+    return getUniqueName();
+  }
+
+  protected void assertStopOf(final Process process) {
+    await().until(() -> assertThat(process.isAlive()).isFalse());
+  }
+
+  /**
+   * Please leave unused parameter throwableClass for improved readability.
+   */
+  protected void assertThatLocatorThrew(Class<? extends Throwable> throwableClass) {
+    assertThat(threwBindException.get()).isTrue();
+  }
+
+  protected void assertThatPidIsAlive(final int pid) {
+    assertThat(pid).isGreaterThan(0);
+    assertThat(isProcessAlive(pid)).isTrue();
+  }
+
+  protected void assertThatProcessIsNotAlive(final Process process) {
+    assertThat(process.isAlive()).isFalse();
+  }
+
+  protected LocatorLauncher givenRunningLocator() {
+    return givenRunningLocator(new LocatorCommand(this).withCommand(Command.START));
+  }
+
+  protected LocatorLauncher givenRunningLocator(final LocatorCommand command) {
+    return awaitStart(command);
+  }
+
+  protected LocatorCommand addJvmArgument(final String arg) {
+    return locatorCommand.addJvmArgument(arg);
+  }
+
+  protected LocatorCommand withForce() {
+    return withForce(true);
+  }
+
+  protected LocatorCommand withForce(final boolean value) {
+    return locatorCommand.force(value);
+  }
+
+  protected LocatorCommand withPort(final int port) {
+    return locatorCommand.withPort(port);
+  }
+
+  protected Process getLocatorProcess() {
+    return process;
+  }
+
+  @Override
+  protected LocatorLauncher startLocator() {
+    return awaitStart(locatorCommand);
+  }
+
+  protected LocatorLauncher startLocator(final LocatorCommand command) {
+    return awaitStart(command);
+  }
+
+  protected LocatorLauncher startLocator(final LocatorCommand command,
+      final InputListener outListener, final InputListener errListener) {
+    executeCommandWithReaders(command.create(), outListener, errListener);
+    LocatorLauncher launcher = awaitStart(getWorkingDirectory());
+    assertThat(process.isAlive()).isTrue();
+    return launcher;
+  }
+
+  protected void startLocatorShouldFail(final LocatorCommand command) throws InterruptedException {
+    awaitStartFail(command, createBindExceptionListener("sysout", threwBindException),
+        createBindExceptionListener("syserr", threwBindException));
+
+  }
+
+  protected void startLocatorShouldFail() throws InterruptedException {
+    startLocatorShouldFail(locatorCommand);
+  }
+
+  private void assertThatProcessIsNotAlive() {
+    assertThatProcessIsNotAlive(process);
+  }
+
+  private void awaitStartFail(final LocatorCommand command, final InputListener outListener,
+      final InputListener errListener) throws InterruptedException {
+    executeCommandWithReaders(command.create(), outListener, errListener);
+    process.waitFor(2, MINUTES);
+    assertThatProcessIsNotAlive();
+    assertThat(process.exitValue()).isEqualTo(1);
+  }
+
+  private LocatorLauncher awaitStart(final File workingDirectory) {
+    try {
+      launcher = new Builder().setWorkingDirectory(workingDirectory.getCanonicalPath()).build();
+      awaitStart(launcher);
+      assertThat(process.isAlive()).isTrue();
+      return launcher;
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private LocatorLauncher awaitStart(final LocatorCommand command) {
+    executeCommandWithReaders(command);
+    LocatorLauncher launcher = awaitStart(getWorkingDirectory());
+    assertThat(process.isAlive()).isTrue();
+    return launcher;
+  }
+
+  @Override
+  protected LocatorLauncher awaitStart(final LocatorLauncher launcher) {
+    await().until(() -> assertThat(launcher.status().getStatus()).isEqualTo(Status.ONLINE));
+    assertThat(process.isAlive()).isTrue();
+    return launcher;
+  }
+
+  private InputListener createBindExceptionListener(final String name,
+      final AtomicBoolean threwBindException) {
+    return createExpectedListener(name, BindException.class.getName(), threwBindException);
+  }
+
+  private void executeCommandWithReaders(final List<String> command) {
+    try {
+      process = new ProcessBuilder(command).directory(getWorkingDirectory()).start();
+      processOutReader = new ProcessStreamReader.Builder(process)
+          .inputStream(process.getInputStream()).build().start();
+      processErrReader = new ProcessStreamReader.Builder(process)
+          .inputStream(process.getErrorStream()).build().start();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private void executeCommandWithReaders(final List<String> command,
+      final InputListener outListener, final InputListener errListener) {
+    try {
+      process = new ProcessBuilder(command).directory(getWorkingDirectory()).start();
+      processOutReader = new ProcessStreamReader.Builder(process)
+          .inputStream(process.getInputStream()).inputListener(outListener).build().start();
+      processErrReader = new ProcessStreamReader.Builder(process)
+          .inputStream(process.getErrorStream()).inputListener(errListener).build().start();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private void executeCommandWithReaders(final LocatorCommand command) {
+    executeCommandWithReaders(command.create());
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteWithCustomLoggingIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteWithCustomLoggingIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteWithCustomLoggingIntegrationTest.java
index 34e11e0..eb4c17a 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteWithCustomLoggingIntegrationTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherRemoteWithCustomLoggingIntegrationTest.java
@@ -15,120 +15,64 @@
 package org.apache.geode.distributed;
 
 import static org.apache.geode.internal.logging.log4j.custom.CustomConfiguration.CONFIG_LAYOUT_PREFIX;
+import static org.apache.geode.internal.logging.log4j.custom.CustomConfiguration.createConfigFileIn;
+import static org.apache.logging.log4j.core.config.ConfigurationFactory.CONFIGURATION_FILE_PROPERTY;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.*;
 
 import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
+import java.io.IOException;
+import java.io.UncheckedIOException;
 
-import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.contrib.java.lang.system.SystemOutRule;
 import org.junit.experimental.categories.Category;
 
-import org.apache.geode.internal.logging.log4j.custom.CustomConfiguration;
-import org.apache.geode.internal.process.ProcessStreamReader;
-import org.apache.geode.internal.process.ProcessType;
-import org.apache.geode.internal.process.ProcessUtils;
+import org.apache.geode.distributed.LocatorLauncher.Command;
+import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
 import org.apache.geode.test.junit.categories.IntegrationTest;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
 
 /**
- * Integration tests for launching a Locator in a forked process with custom logging configuration
+ * Integration tests for using {@code LocatorLauncher} as an application main in a forked JVM with
+ * custom logging configuration.
  */
 @Category(IntegrationTest.class)
-@RunWith(Parameterized.class)
-@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
 public class LocatorLauncherRemoteWithCustomLoggingIntegrationTest
-    extends AbstractLocatorLauncherRemoteIntegrationTestCase {
+    extends LocatorLauncherRemoteIntegrationTestCase {
 
-  private File customConfigFile;
+  private File customLoggingConfigFile;
 
   @Rule
   public SystemOutRule systemOutRule = new SystemOutRule().enableLog();
 
   @Before
   public void setUpLocatorLauncherRemoteWithCustomLoggingIntegrationTest() throws Exception {
-    this.customConfigFile = CustomConfiguration.createConfigFileIn(this.temporaryFolder.getRoot());
+    this.customLoggingConfigFile = createConfigFileIn(getWorkingDirectory());
   }
 
   @Test
-  public void testStartUsesCustomLoggingConfiguration() throws Throwable {
-    // build and start the locator
-    final List<String> jvmArguments = getJvmArguments();
+  public void startWithCustomLoggingConfiguration() throws Exception {
+    startLocator(new LocatorCommand(this)
+        .addJvmArgument("-D" + CONFIGURATION_FILE_PROPERTY + "=" + getCustomLoggingConfigFilePath())
+        .withCommand(Command.START), new ToSystemOut(), new ToSystemOut());
 
-    final List<String> command = new ArrayList<String>();
-    command
-        .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath());
-    for (String jvmArgument : jvmArguments) {
-      command.add(jvmArgument);
-    }
-    command.add("-D" + ConfigurationFactory.CONFIGURATION_FILE_PROPERTY + "="
-        + this.customConfigFile.getCanonicalPath());
-    command.add("-cp");
-    command.add(System.getProperty("java.class.path"));
-    command.add(LocatorLauncher.class.getName());
-    command.add(LocatorLauncher.Command.START.getName());
-    command.add(getUniqueName());
-    command.add("--port=" + this.locatorPort);
-    command.add("--redirect-output");
-
-    this.process = new ProcessBuilder(command).directory(new File(this.workingDirectory)).start();
-    this.processOutReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
-            .inputListener(new ToSystemOut()).build().start();
-    this.processErrReader =
-        new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
-            .inputListener(new ToSystemOut()).build().start();
-
-    int pid = 0;
-    this.launcher = new LocatorLauncher.Builder().setWorkingDirectory(workingDirectory).build();
-    try {
-      waitForLocatorToStart(this.launcher);
-
-      // validate the pid file and its contents
-      this.pidFile = new File(this.temporaryFolder.getRoot(), ProcessType.LOCATOR.getPidFileName());
-      assertTrue(this.pidFile.exists());
-      pid = readPid(this.pidFile);
-      assertTrue(pid > 0);
-      assertTrue(ProcessUtils.isProcessAlive(pid));
-
-      final String logFileName = getUniqueName() + ".log";
-      assertTrue("Log file should exist: " + logFileName,
-          new File(this.temporaryFolder.getRoot(), logFileName).exists());
-
-      // check the status
-      final LocatorLauncher.LocatorState locatorState = this.launcher.status();
-      assertNotNull(locatorState);
-      assertEquals(AbstractLauncher.Status.ONLINE, locatorState.getStatus());
-
-      assertThat(systemOutRule.getLog())
-          .contains("log4j.configurationFile = " + this.customConfigFile.getCanonicalPath());
-      assertThat(systemOutRule.getLog()).contains(CONFIG_LAYOUT_PREFIX);
-
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
-    }
+    assertThat(systemOutRule.getLog()).contains(CONFIG_LAYOUT_PREFIX)
+        .contains("log4j.configurationFile = " + getCustomLoggingConfigFilePath());
+  }
 
-    // stop the locator
+  private String getCustomLoggingConfigFilePath() {
     try {
-      assertEquals(AbstractLauncher.Status.STOPPED, this.launcher.stop().getStatus());
-      waitForPidToStop(pid);
-    } catch (Throwable e) {
-      this.errorCollector.addError(e);
+      return customLoggingConfigFile.getCanonicalPath();
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
     }
   }
 
-  private static class ToSystemOut implements ProcessStreamReader.InputListener {
+  private static class ToSystemOut implements InputListener {
     @Override
-    public void notifyInputLine(String line) {
+    public void notifyInputLine(final String line) {
       System.out.println(line);
     }
   }
-
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java
index bc7c371..4206187 100644
--- a/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java
+++ b/geode-core/src/test/java/org/apache/geode/distributed/LocatorLauncherTest.java
@@ -14,63 +14,26 @@
  */
 package org.apache.geode.distributed;
 
-import static org.apache.geode.distributed.ConfigurationProperties.NAME;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import org.apache.geode.distributed.LocatorLauncher.Builder;
-import org.apache.geode.distributed.LocatorLauncher.Command;
-import org.apache.geode.distributed.internal.DistributionConfig;
-import org.apache.geode.distributed.internal.InternalDistributedSystem;
-import org.apache.geode.distributed.internal.InternalLocator;
-import org.apache.geode.internal.DistributionLocator;
-import org.apache.geode.internal.i18n.LocalizedStrings;
-import org.apache.geode.test.junit.categories.FlakyTest;
-import org.apache.geode.test.junit.categories.UnitTest;
-import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
-import org.junit.contrib.java.lang.system.RestoreSystemProperties;
 import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
 
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import joptsimple.OptionException;
+import org.apache.geode.distributed.internal.InternalLocator;
+import org.apache.geode.test.junit.categories.UnitTest;
 
 /**
- * The LocatorLauncherTest class is a test suite of test cases for testing the contract and
- * functionality of launching a GemFire Locator.
+ * Unit tests for {@link LocatorLauncher}.
  *
- * @see org.apache.geode.distributed.LocatorLauncher
- * @see org.apache.geode.distributed.LocatorLauncher.Builder
- * @see org.apache.geode.distributed.LocatorLauncher.Command
- * @see org.junit.Assert
- * @see org.junit.Test
  * @since GemFire 7.0
  */
 @Category(UnitTest.class)
 public class LocatorLauncherTest {
 
-  @Rule
-  public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
-
-  @Rule
-  public final TestName testName = new TestName();
-
-  @Before
-  public void setUp() throws Exception {
-    assertThat(InternalDistributedSystem.getConnectedInstance()).isNull();
-  }
-
   @Test
-  public void shouldBeMockable() throws Exception {
+  public void canBeMocked() throws Exception {
     LocatorLauncher mockLocatorLauncher = mock(LocatorLauncher.class);
     InternalLocator mockInternalLocator = mock(InternalLocator.class);
 
@@ -80,303 +43,4 @@ public class LocatorLauncherTest {
     assertThat(mockLocatorLauncher.getLocator()).isSameAs(mockInternalLocator);
     assertThat(mockLocatorLauncher.getId()).isEqualTo("ID");
   }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testBuilderParseArgumentsWithNonNumericPort() {
-    try {
-      new Builder().parseArguments("start", "locator1", "--port", "oneTwoThree");
-    } catch (IllegalArgumentException expected) {
-      assertTrue(expected.getCause() instanceof OptionException);
-      assertTrue(expected.getMessage(),
-          expected.getMessage()
-              .contains(LocalizedStrings.Launcher_Builder_PARSE_COMMAND_LINE_ARGUMENT_ERROR_MESSAGE
-                  .toLocalizedString("Locator", expected.getCause().getMessage())));
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testForceDefaultsToFalse() {
-    assertFalse(new Builder().getForce());
-  }
-
-  @Test
-  public void testForceSetToTrue() {
-    Builder builder = new Builder();
-
-    builder.parseArguments("start", "--force");
-
-    assertTrue(Boolean.TRUE.equals(builder.getForce()));
-  }
-
-  @Test
-  public void testSetAndGetCommand() {
-    final Builder builder = new Builder();
-
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
-    assertSame(builder, builder.setCommand(Command.START));
-    assertEquals(Command.START, builder.getCommand());
-    assertSame(builder, builder.setCommand(Command.STATUS));
-    assertEquals(Command.STATUS, builder.getCommand());
-    assertSame(builder, builder.setCommand(Command.STOP));
-    assertEquals(Command.STOP, builder.getCommand());
-    assertSame(builder, builder.setCommand(null));
-    assertEquals(Builder.DEFAULT_COMMAND, builder.getCommand());
-  }
-
-  @Test
-  public void testSetAndGetBindAddress() throws UnknownHostException {
-    final Builder builder = new Builder();
-
-    assertNull(builder.getBindAddress());
-    assertSame(builder, builder.setBindAddress(null));
-    assertNull(builder.getBindAddress());
-    assertSame(builder, builder.setBindAddress(""));
-    assertNull(builder.getBindAddress());
-    assertSame(builder, builder.setBindAddress("  "));
-    assertNull(builder.getBindAddress());
-    assertSame(builder, builder.setBindAddress(InetAddress.getLocalHost().getCanonicalHostName()));
-    assertEquals(InetAddress.getLocalHost(), builder.getBindAddress());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetBindAddressToUnknownHost() {
-    try {
-      new Builder().setBindAddress("badhostname.badcompany.bad");
-    } catch (IllegalArgumentException expected) {
-      final String expectedMessage1 =
-          LocalizedStrings.Launcher_Builder_UNKNOWN_HOST_ERROR_MESSAGE.toLocalizedString("Locator");
-      final String expectedMessage2 =
-          "badhostname.badcompany.bad is not an address for this machine.";
-      assertTrue(expected.getMessage().equals(expectedMessage1)
-          || expected.getMessage().equals(expectedMessage2));
-      if (expected.getMessage().equals(expectedMessage1)) {
-        assertTrue(expected.getCause() instanceof UnknownHostException);
-      }
-      throw expected;
-    }
-  }
-
-  @Category(FlakyTest.class) // GEODE-1308
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetBindAddressToNonLocalHost() {
-    try {
-      new Builder().setBindAddress("yahoo.com");
-    } catch (IllegalArgumentException expected) {
-      final String expectedMessage = "yahoo.com is not an address for this machine.";
-      assertEquals(expectedMessage, expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testSetBindAddressToLocalHost() throws Exception {
-    String host = InetAddress.getLocalHost().getHostName();
-    new Builder().setBindAddress(host);
-  }
-
-  @Test
-  public void testSetAndGetHostnameForClients() {
-    final Builder builder = new Builder();
-
-    assertNull(builder.getHostnameForClients());
-    assertSame(builder, builder.setHostnameForClients("Pegasus"));
-    assertEquals("Pegasus", builder.getHostnameForClients());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetHostnameForClientsWithBlankString() {
-    try {
-      new Builder().setHostnameForClients(" ");
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.LocatorLauncher_Builder_INVALID_HOSTNAME_FOR_CLIENTS_ERROR_MESSAGE
-              .toLocalizedString(),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetHostnameForClientsWithEmptyString() {
-    try {
-      new Builder().setHostnameForClients("");
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.LocatorLauncher_Builder_INVALID_HOSTNAME_FOR_CLIENTS_ERROR_MESSAGE
-              .toLocalizedString(),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetHostnameForClientsWithNullString() {
-    try {
-      new Builder().setHostnameForClients(null);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.LocatorLauncher_Builder_INVALID_HOSTNAME_FOR_CLIENTS_ERROR_MESSAGE
-              .toLocalizedString(),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testSetAndGetMemberName() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getMemberName());
-    assertSame(builder, builder.setMemberName("locatorOne"));
-    assertEquals("locatorOne", builder.getMemberName());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMemberNameWithBlankString() {
-    try {
-      new Builder().setMemberName("  ");
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE.toLocalizedString("Locator"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMemberNameWithEmptyString() {
-    try {
-      new Builder().setMemberName("");
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE.toLocalizedString("Locator"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetMemberNameWithNullString() {
-    try {
-      new Builder().setMemberName(null);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_MEMBER_NAME_ERROR_MESSAGE.toLocalizedString("Locator"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testSetAndGetPid() {
-    Builder builder = new Builder();
-
-    assertNull(builder.getPid());
-    assertSame(builder, builder.setPid(0));
-    assertEquals(0, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(1));
-    assertEquals(1, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(1024));
-    assertEquals(1024, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(12345));
-    assertEquals(12345, builder.getPid().intValue());
-    assertSame(builder, builder.setPid(null));
-    assertNull(builder.getPid());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetPidToInvalidValue() {
-    try {
-      new Builder().setPid(-1);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(LocalizedStrings.Launcher_Builder_PID_ERROR_MESSAGE.toLocalizedString(),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @SuppressWarnings("deprecation")
-  @Test
-  public void testSetAndGetPort() {
-    Builder builder = new Builder();
-    assertEquals(Integer.valueOf(DistributionLocator.DEFAULT_LOCATOR_PORT), builder.getPort());
-    assertSame(builder, builder.setPort(65535));
-    assertEquals(65535, builder.getPort().intValue());
-    assertSame(builder, builder.setPort(1024));
-    assertEquals(1024, builder.getPort().intValue());
-    assertSame(builder, builder.setPort(80));
-    assertEquals(80, builder.getPort().intValue());
-    assertSame(builder, builder.setPort(1));
-    assertEquals(1, builder.getPort().intValue());
-    assertSame(builder, builder.setPort(0));
-    assertEquals(0, builder.getPort().intValue());
-    assertSame(builder, builder.setPort(null));
-    assertEquals(Integer.valueOf(DistributionLocator.DEFAULT_LOCATOR_PORT), builder.getPort());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetPortToOverflow() {
-    try {
-      new Builder().setPort(65536);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_INVALID_PORT_ERROR_MESSAGE.toLocalizedString("Locator"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void testSetPortToUnderflow() {
-    try {
-      new Builder().setPort(-1);
-    } catch (IllegalArgumentException expected) {
-      assertEquals(
-          LocalizedStrings.Launcher_Builder_INVALID_PORT_ERROR_MESSAGE.toLocalizedString("Locator"),
-          expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testBuild() throws Exception {
-    Builder builder = new Builder();
-
-    LocatorLauncher launcher = builder.setCommand(Command.START).setDebug(true)
-        .setHostnameForClients("beanstock.vmware.com").setMemberName("Beanstock").setPort(8192)
-        .build();
-
-    assertThat(launcher).isNotNull();
-    assertEquals(builder.getCommand(), launcher.getCommand());
-    assertTrue(launcher.isDebugging());
-    assertEquals(builder.getHostnameForClients(), launcher.getHostnameForClients());
-    assertEquals(builder.getMemberName(), launcher.getMemberName());
-    assertEquals(builder.getPort(), launcher.getPort());
-    assertEquals(builder.getWorkingDirectory(), launcher.getWorkingDirectory());
-    assertFalse(launcher.isHelping());
-    assertFalse(launcher.isRunning());
-  }
-
-  @Test
-  public void testBuildWithMemberNameSetInApiPropertiesOnStart() {
-    LocatorLauncher launcher =
-        new Builder().setCommand(LocatorLauncher.Command.START).set(NAME, "locatorABC").build();
-
-    assertThat(launcher).isNotNull();
-    assertEquals(LocatorLauncher.Command.START, launcher.getCommand());
-    assertNull(launcher.getMemberName());
-    assertEquals("locatorABC", launcher.getProperties().getProperty(NAME));
-  }
-
-  @Test
-  public void testBuildWithMemberNameSetInSystemPropertiesOnStart() {
-    System.setProperty(DistributionConfig.GEMFIRE_PREFIX + NAME, "locatorXYZ");
-
-    LocatorLauncher launcher = new Builder().setCommand(LocatorLauncher.Command.START).build();
-
-    assertThat(launcher).isNotNull();
-    assertEquals(LocatorLauncher.Command.START, launcher.getCommand());
-    assertNull(launcher.getMemberName());
-  }
 }