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(); + } +}