geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kl...@apache.org
Subject [04/14] geode git commit: GEODE-3413: overhaul launcher and process classes and tests
Date Fri, 11 Aug 2017 17:12:02 GMT
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();
+  }
+}


Mime
View raw message