You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by zh...@apache.org on 2017/08/11 17:26:41 UTC
[11/23] geode git commit: GEODE-3413: overhaul launcher and process
classes and tests
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java
new file mode 100755
index 0000000..d22d92a
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderIntegrationTest.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.lang.SystemUtils.isWindows;
+import static org.apache.geode.internal.process.ProcessStreamReader.ReadingMode.BLOCKING;
+import static org.junit.Assume.assumeFalse;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for BlockingProcessStreamReader. All tests are skipped on Windows
+ * due to TRAC #51967: "GFSH start hangs on Windows"
+ *
+ * @see BlockingProcessStreamReaderWindowsTest
+ * @see NonBlockingProcessStreamReaderIntegrationTest
+ *
+ * @since GemFire 8.2
+ */
+@Category(IntegrationTest.class)
+public class BlockingProcessStreamReaderIntegrationTest
+ extends BaseProcessStreamReaderIntegrationTest {
+
+ @Before
+ public void setUp() throws Exception {
+ assumeFalse(isWindows());
+ }
+
+ @Test
+ public void canCloseStreams() throws Exception {
+ // arrange
+ givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+ // act
+ process.getOutputStream().close();
+ process.getErrorStream().close();
+ process.getInputStream().close();
+
+ // assert
+ assertThatProcessIsAlive(process);
+ }
+
+ @Test
+ public void canStopReaders() throws Exception {
+ // arrange
+ givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+ // act
+ stdout.stop();
+ stderr.stop();
+
+ // assert
+ assertThatProcessIsAlive(process);
+ }
+
+ @Test
+ public void capturesStdout() throws Exception {
+ // arrange
+ givenStartedProcessWithStreamListeners(ProcessPrintsToStdout.class);
+
+ // act
+ waitUntilProcessStops();
+
+ // assert
+ assertThatProcessAndReadersStopped();
+ assertThatStdOutContainsExactly(ProcessPrintsToStdout.STDOUT);
+ assertThatStdErrContainsExactly(ProcessPrintsToStdout.STDERR);
+ }
+
+ @Test
+ public void capturesStderr() throws Exception {
+ // arrange
+ givenStartedProcessWithStreamListeners(ProcessPrintsToStderr.class);
+
+ // act
+ waitUntilProcessStops();
+
+ // assert
+ assertThatProcessAndReadersStopped();
+ assertThatStdOutContainsExactly(ProcessPrintsToStderr.STDOUT);
+ assertThatStdErrContainsExactly(ProcessPrintsToStderr.STDERR);
+ }
+
+ @Test
+ public void capturesStdoutAndStderr() throws Exception {
+ // arrange
+ givenStartedProcessWithStreamListeners(ProcessPrintsToBoth.class);
+
+ // act
+ waitUntilProcessStops();
+
+ // assert
+ assertThatProcessAndReadersStopped();
+ assertThatStdOutContainsExactly(ProcessPrintsToBoth.STDOUT);
+ assertThatStdErrContainsExactly(ProcessPrintsToBoth.STDERR);
+ }
+
+ @Test
+ public void capturesStderrWhenProcessFailsDuringStart() throws Exception {
+ // arrange
+ givenStartedProcessWithStreamListeners(ProcessThrowsError.class);
+
+ // act
+ waitUntilProcessStops();
+
+ // assert
+ assertThatProcessAndReadersStoppedWithExitValue(1);
+ assertThatStdOutContainsExactly(ProcessThrowsError.STDOUT);
+ assertThatStdErrContains(ProcessThrowsError.ERROR_MSG);
+ }
+
+ @Override
+ protected ReadingMode getReadingMode() {
+ return BLOCKING;
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java
deleted file mode 100755
index 7d52e56..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderJUnitTest.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-import static org.junit.Assume.*;
-
-import java.io.IOException;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.internal.lang.SystemUtils;
-import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
-import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * Tests BlockingProcessStreamReader. Most tests are skipped on Windows due to TRAC bug #51967 which
- * is caused by a JDK bug. The test {@link #hangsOnWindows} verifies the existence of the bug.
- *
- * @since GemFire 8.2
- */
-@Category(IntegrationTest.class)
-public class BlockingProcessStreamReaderJUnitTest extends ProcessStreamReaderTestCase {
-
- /** Timeout to confirm hang on Windows */
- private static final int HANG_TIMEOUT = 10;
-
- private ExecutorService futures;
-
- @Before
- public void createFutures() {
- this.futures = Executors.newSingleThreadExecutor();
- }
-
- @After
- public void shutdownFutures() {
- assertTrue(this.futures.shutdownNow().isEmpty());
- }
-
- @Test
- public void hangsOnWindows() throws Exception {
- assumeTrue(SystemUtils.isWindows());
-
- this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
- this.stderr = new ProcessStreamReader.Builder(this.process)
- .inputStream(this.process.getErrorStream()).build();
-
- this.stdout = new ProcessStreamReader.Builder(this.process)
- .inputStream(this.process.getInputStream()).build();
-
- this.stderr.start();
- this.stdout.start();
-
- assertIsAlive(this.process);
-
- assertEventuallyIsRunning(this.stderr);
- assertEventuallyIsRunning(this.stdout);
-
- Future<Boolean> future = this.futures.submit(new Callable<Boolean>() {
- @Override
- public Boolean call() throws IOException {
- process.getErrorStream().close();
- process.getOutputStream().close();
- process.getInputStream().close();
- return true;
- }
- });
-
- try {
- future.get(HANG_TIMEOUT, TimeUnit.SECONDS);
- // if the following fails then perhaps we're testing with a new JRE that
- // fixes blocking reads of process streams on windows
- fail("future should have timedout due to hang on windows");
- } catch (TimeoutException expected) {
- // verified hang on windows which causes TRAC bug #51967
- }
-
- this.process.destroy();
- }
-
- @Test
- public void canCloseStreamsWhileProcessIsAlive() throws Exception {
- assumeFalse(SystemUtils.isWindows());
-
- this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
- this.stderr = new ProcessStreamReader.Builder(this.process)
- .inputStream(this.process.getErrorStream()).build();
-
- this.stdout = new ProcessStreamReader.Builder(this.process)
- .inputStream(this.process.getInputStream()).build();
-
- this.stderr.start();
- this.stdout.start();
-
- assertIsAlive(this.process);
-
- assertEventuallyIsRunning(this.stderr);
- assertEventuallyIsRunning(this.stdout);
-
- this.process.getErrorStream().close();
- this.process.getOutputStream().close();
- this.process.getInputStream().close();
-
- assertIsAlive(this.process);
-
- this.process.destroy();
- }
-
- @Test
- public void canStopReadersWhileProcessIsAlive() throws Exception {
- assumeFalse(SystemUtils.isWindows());
-
- this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start();
-
- this.stderr = new ProcessStreamReader.Builder(this.process)
- .inputStream(this.process.getErrorStream()).build();
-
- this.stdout = new ProcessStreamReader.Builder(this.process)
- .inputStream(this.process.getInputStream()).build();
-
- this.stderr.start();
- this.stdout.start();
-
- assertIsAlive(this.process);
-
- assertEventuallyIsRunning(this.stderr);
- assertEventuallyIsRunning(this.stdout);
-
- this.stderr.stop();
- this.stdout.stop();
-
- this.process.getErrorStream().close();
- this.process.getOutputStream().close();
- this.process.getInputStream().close();
-
- assertIsAlive(this.process);
-
- this.process.destroy();
- }
-
- @Test
- public void capturesStdoutWhileProcessIsAlive() throws Exception {
- assumeFalse(SystemUtils.isWindows());
-
- this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStdout.class)).start();
-
- final StringBuffer stderrBuffer = new StringBuffer();
- InputListener stderrListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stderrBuffer.append(line);
- }
- };
-
- final StringBuffer stdoutBuffer = new StringBuffer();
- InputListener stdoutListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stdoutBuffer.append(line);
- }
- };
-
- this.stderr =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
- .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stdout =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
- .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stderr.start();
- this.stdout.start();
-
- assertEventuallyIsRunning(this.stderr);
- assertEventuallyIsRunning(this.stdout);
-
- // wait for process to die
- assertEventuallyFalse("Process never died", new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- return ProcessUtils.isProcessAlive(process);
- }
- }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
- final int exitValue = this.process.exitValue();
- assertEquals(0, exitValue);
-
- this.stderr.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stderr.isRunning());
-
- this.stdout.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stdout.isRunning());
-
- // System.out.println("Stopping ProcessStreamReader");
- this.stderr.stop();
- this.stdout.stop();
-
- // System.out.println("stderr=\n" + stderrBuffer.toString());
- assertEquals("", stderrBuffer.toString());
-
- // System.out.println("stdout=\n" + stdoutBuffer.toString());
- StringBuilder sb = new StringBuilder().append(ProcessPrintsToStdout.LINES[0])
- .append(ProcessPrintsToStdout.LINES[1]).append(ProcessPrintsToStdout.LINES[2]);
- assertEquals(sb.toString(), stdoutBuffer.toString());
-
- // System.out.println("Closing streams");
- this.process.getErrorStream().close();
- this.process.getInputStream().close();
-
- this.process.destroy();
- }
-
- @Test
- public void capturesStderrWhileProcessIsAlive() throws Exception {
- assumeFalse(SystemUtils.isWindows());
-
- this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStderr.class)).start();
-
- final StringBuffer stderrBuffer = new StringBuffer();
- InputListener stderrListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stderrBuffer.append(line);
- }
- };
-
- final StringBuffer stdoutBuffer = new StringBuffer();
- InputListener stdoutListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stdoutBuffer.append(line);
- }
- };
-
- this.stderr =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
- .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stdout =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
- .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stderr.start();
- this.stdout.start();
-
- // wait for process to die
- assertEventuallyFalse("Process never died", new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- return ProcessUtils.isProcessAlive(process);
- }
- }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
- final int exitValue = this.process.exitValue();
- assertEquals(0, exitValue);
-
- this.stderr.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stderr.isRunning());
-
- this.stdout.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stdout.isRunning());
-
- // System.out.println("Stopping ProcessStreamReader");
- this.stderr.stop();
- this.stdout.stop();
-
- // System.out.println("stderr=\n" + stderrBuffer.toString());
- StringBuilder sb = new StringBuilder().append(ProcessPrintsToStderr.LINES[0])
- .append(ProcessPrintsToStderr.LINES[1]).append(ProcessPrintsToStderr.LINES[2]);
- assertEquals(sb.toString(), stderrBuffer.toString());
-
- // System.out.println("stdout=\n" + stdoutBuffer.toString());
- assertEquals("", stdoutBuffer.toString());
-
- // System.out.println("Closing streams");
- this.process.getErrorStream().close();
- this.process.getInputStream().close();
-
- this.process.destroy();
- }
-
- @Test
- public void capturesBothWhileProcessIsAlive() throws Exception {
- assumeFalse(SystemUtils.isWindows());
-
- this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToBoth.class)).start();
-
- final StringBuffer stderrBuffer = new StringBuffer();
- InputListener stderrListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stderrBuffer.append(line);
- }
- };
-
- final StringBuffer stdoutBuffer = new StringBuffer();
- InputListener stdoutListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stdoutBuffer.append(line);
- }
- };
-
- this.stderr =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
- .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stdout =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
- .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stderr.start();
- this.stdout.start();
-
- // wait for process to die
- assertEventuallyFalse("Process never died", new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- return ProcessUtils.isProcessAlive(process);
- }
- }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
- final int exitValue = this.process.exitValue();
- assertEquals(0, exitValue);
-
- this.stderr.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stderr.isRunning());
-
- this.stdout.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stdout.isRunning());
-
- // System.out.println("Stopping ProcessStreamReader");
- this.stderr.stop();
- this.stdout.stop();
-
- // System.out.println("stderr=\n" + stderrBuffer.toString());
- StringBuilder sb = new StringBuilder().append(ProcessPrintsToBoth.ERR_LINES[0])
- .append(ProcessPrintsToBoth.ERR_LINES[1]).append(ProcessPrintsToBoth.ERR_LINES[2]);
- assertEquals(sb.toString(), stderrBuffer.toString());
-
- // System.out.println("stdout=\n" + stdoutBuffer.toString());
- sb = new StringBuilder().append(ProcessPrintsToBoth.OUT_LINES[0])
- .append(ProcessPrintsToBoth.OUT_LINES[1]).append(ProcessPrintsToBoth.OUT_LINES[2]);
- assertEquals(sb.toString(), stdoutBuffer.toString());
-
- // System.out.println("Closing streams");
- this.process.getErrorStream().close();
- this.process.getInputStream().close();
-
- this.process.destroy();
- }
-
- @Test
- public void capturesStderrWhenProcessFailsDuringStart() throws Exception {
- assumeFalse(SystemUtils.isWindows());
-
- this.process = new ProcessBuilder(createCommandLine(ProcessThrowsError.class)).start();
-
- final StringBuffer stderrBuffer = new StringBuffer();
- InputListener stderrListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stderrBuffer.append(line);
- }
- };
-
- final StringBuffer stdoutBuffer = new StringBuffer();
- InputListener stdoutListener = new InputListener() {
- @Override
- public void notifyInputLine(String line) {
- stdoutBuffer.append(line);
- }
- };
-
- this.stderr =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream())
- .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stdout =
- new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream())
- .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build();
-
- this.stderr.start();
- this.stdout.start();
-
- // wait for process to die
- assertEventuallyFalse("Process never died", new Callable<Boolean>() {
- @Override
- public Boolean call() throws Exception {
- return ProcessUtils.isProcessAlive(process);
- }
- }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL);
-
- final int exitValue = this.process.exitValue();
- assertNotEquals(0, exitValue);
-
- this.stderr.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stderr.isRunning());
-
- this.stdout.join(READER_JOIN_TIMEOUT);
- assertFalse(this.stdout.isRunning());
-
- // System.out.println("Stopping ProcessStreamReader");
- this.stderr.stop();
- this.stdout.stop();
-
- // System.out.println("stderr=\n" + stderrBuffer.toString());
- assertTrue(stderrBuffer.toString() + " does not contain " + ProcessThrowsError.ERROR_MSG,
- stderrBuffer.toString().contains(ProcessThrowsError.ERROR_MSG));
-
- // System.out.println("stdout=\n" + stdoutBuffer.toString());
-
- // System.out.println("Closing streams");
- this.process.getErrorStream().close();
- this.process.getInputStream().close();
-
- this.process.destroy();
- }
-}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java
new file mode 100644
index 0000000..60c94e4
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/BlockingProcessStreamReaderWindowsTest.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.internal.lang.SystemUtils.isWindows;
+import static org.apache.geode.internal.process.ProcessStreamReader.ReadingMode.BLOCKING;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration test {@link #hangsOnWindows} for BlockingProcessStreamReader which
+ * verifies TRAC #51967: "GFSH start hangs on Windows." The hang is supposedly caused by a JDK bug
+ * in which a thread invoking readLine() will block forever and ignore any interrupts. The thread
+ * will respond to interrupts as expected on Mac, Linux and Solaris.
+ *
+ * @see BlockingProcessStreamReaderIntegrationTest
+ * @see NonBlockingProcessStreamReaderIntegrationTest
+ *
+ * @since GemFire 8.2
+ */
+@Category(IntegrationTest.class)
+public class BlockingProcessStreamReaderWindowsTest
+ extends AbstractProcessStreamReaderIntegrationTest {
+
+ /** Timeout to confirm hang on Windows */
+ private static final int HANG_TIMEOUT_SECONDS = 10;
+
+ private ExecutorService futures;
+
+ @Before
+ public void setUp() throws Exception {
+ assumeTrue(isWindows());
+
+ futures = Executors.newSingleThreadExecutor();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (futures != null) {
+ assertThat(futures.shutdownNow()).isEmpty();
+ }
+ }
+
+ @Test
+ public void hangsOnWindows() throws Exception {
+ // arrange
+ givenRunningProcessWithStreamReaders(ProcessSleeps.class);
+
+ // act
+ Future<Boolean> future = futures.submit(() -> {
+ process.getOutputStream().close();
+ process.getErrorStream().close();
+ process.getInputStream().close();
+ return true;
+ });
+
+ // assert
+ assertThatThrownBy(() -> future.get(HANG_TIMEOUT_SECONDS, SECONDS))
+ .isInstanceOf(TimeoutException.class);
+ }
+
+ @Override
+ protected ReadingMode getReadingMode() {
+ return BLOCKING;
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java
new file mode 100644
index 0000000..46c81f7
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/ControlFileWatchdogIntegrationTest.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.awaitility.Awaitility.await;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Functional integration tests for {@link ControlFileWatchdog}.
+ */
+@Category(IntegrationTest.class)
+public class ControlFileWatchdogIntegrationTest {
+
+ private static final int TWO_MINUTES_MILLIS = 2 * 60 * 1000;
+
+ private File directory;
+ private String requestFileName;
+ private File requestFile;
+ private ControlRequestHandler requestHandler;
+ private boolean stopAfterRequest;
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void before() throws Exception {
+ directory = temporaryFolder.getRoot();
+ requestFileName = "myFile";
+ requestFile = new File(directory, requestFileName);
+ requestHandler = mock(ControlRequestHandler.class);
+ stopAfterRequest = false;
+ }
+
+ @Test
+ public void isAlive_returnsFalse_beforeStart() throws Exception {
+ // arrange
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+ // act: nothing
+
+ // assert
+ assertThat(watchdog.isAlive()).isFalse();
+ }
+
+ @Test
+ public void isAlive_returnsTrue_afterStart() throws Exception {
+ // arrange
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+ // act
+ watchdog.start();
+
+ // assert
+ assertThat(watchdog.isAlive()).isTrue();
+ }
+
+ @Test
+ public void isAlive_returnsFalse_afterStop() throws Exception {
+ // arrange
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+ watchdog.start();
+
+ // act
+ watchdog.stop();
+
+ // assert
+ assertThat(watchdog.isAlive()).isFalse();
+ }
+
+ @Test
+ public void nullFileName_throwsIllegalArgumentException() throws Exception {
+ // arrange
+ requestFileName = null;
+
+ // act/assert
+ assertThatThrownBy(
+ () -> new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void nullDirectory_throwsIllegalArgumentException() throws Exception {
+ // arrange
+ directory = null;
+
+ // act/assert
+ assertThatThrownBy(
+ () -> new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void nullRequestHandler_throwsIllegalArgumentException() throws Exception {
+ // arrange
+ requestHandler = null;
+
+ // act/assert
+ assertThatThrownBy(
+ () -> new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ public void invokesRequestHandler_afterFileCreation() throws Exception {
+ // arrange
+ requestHandler = mock(ControlRequestHandler.class);
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+ watchdog.start();
+
+ // act
+ File file = new EmptyFileWriter(requestFile).createNewFile();
+
+ // assert
+ verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+ assertThat(file).doesNotExist();
+ }
+
+ @Test
+ public void deletesFile_afterInvokingRequestHandler() throws Exception {
+ // arrange
+ requestHandler = mock(ControlRequestHandler.class);
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+ watchdog.start();
+
+ // act
+ File file = new EmptyFileWriter(requestFile).createNewFile();
+
+ // assert
+ verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+ await().atMost(2, MINUTES).until(() -> assertThat(file).doesNotExist());
+ assertThat(file).doesNotExist();
+ }
+
+ @Test
+ public void doesNotInvokeRequestHandler_whileFileDoesNotExist() throws Exception {
+ // arrange
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+ // act
+ watchdog.start();
+
+ // assert
+ verifyZeroInteractions(requestHandler); // would be prefer to wait some time
+ }
+
+ @Test
+ public void nothingHappens_beforeStart() throws Exception {
+ // arrange
+ requestHandler = mock(ControlRequestHandler.class);
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+ // act
+ File file = new EmptyFileWriter(requestFile).createNewFile();
+
+ // assert
+ verifyZeroInteractions(requestHandler); // would be prefer to wait some time
+ assertThat(file).exists();
+ }
+
+ @Test
+ public void stops_afterInvokingRequestHandler_whenStopAfterRequest() throws Exception {
+ // arrange
+ requestHandler = mock(ControlRequestHandler.class);
+ stopAfterRequest = true;
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+ watchdog.start();
+
+ // act
+ File file = new EmptyFileWriter(requestFile).createNewFile();
+
+ // assert
+ verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+ await().atMost(2, MINUTES).until(() -> assertThat(watchdog.isAlive()).isFalse());
+ assertThat(file).doesNotExist();
+ }
+
+ @Test
+ public void doesNotStop_afterInvokingRequestHandler_whenNotStopAfterRequest() throws Exception {
+ // arrange
+ requestHandler = mock(ControlRequestHandler.class);
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+ watchdog.start();
+
+ // act
+ File file = new EmptyFileWriter(requestFile).createNewFile();
+
+ // assert
+ verify(requestHandler, timeout(TWO_MINUTES_MILLIS)).handleRequest();
+ assertThat(watchdog.isAlive()).isTrue();
+ assertThat(file).doesNotExist();
+ }
+
+ @Test
+ public void toStringIsUsefulForDebugging() throws Exception {
+ // arrange
+ ControlFileWatchdog watchdog =
+ new ControlFileWatchdog(directory, requestFileName, requestHandler, stopAfterRequest);
+
+ // act/assert
+ assertThat(watchdog.toString()).isNotEmpty().contains("directory=").contains("file=")
+ .contains("alive=").contains("stopAfterRequest=");
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java
new file mode 100644
index 0000000..903f08f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/ControllableProcessIntegrationTest.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.distributed.AbstractLauncher.ServiceState;
+import org.apache.geode.internal.process.ControlFileWatchdog.ControlRequestHandler;
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+@Category(IntegrationTest.class)
+public class ControllableProcessIntegrationTest {
+
+ private LocalProcessLauncher localProcessLauncher;
+ private ControlFileWatchdog stopRequestFileWatchdog;
+ private ControlFileWatchdog statusRequestFileWatchdog;
+ private ProcessType processType;
+ private File directory;
+ private File pidFile;
+ private int pid;
+ private File statusRequestFile;
+ private File stopRequestFile;
+ private File statusFile;
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void before() throws Exception {
+ processType = ProcessType.LOCATOR;
+ directory = temporaryFolder.getRoot();
+ pidFile = new File(directory, processType.getPidFileName());
+ pid = identifyPid();
+ statusRequestFile = new File(directory, processType.getStatusRequestFileName());
+ stopRequestFile = new File(directory, processType.getStopRequestFileName());
+ statusFile = new File(directory, processType.getStatusFileName());
+ statusRequestFileWatchdog = new ControlFileWatchdog(directory,
+ processType.getStatusRequestFileName(), mock(ControlRequestHandler.class), false);
+ stopRequestFileWatchdog = new ControlFileWatchdog(directory,
+ processType.getStopRequestFileName(), mock(ControlRequestHandler.class), false);
+ }
+
+ @Test
+ public void getDirectoryExists() throws Exception {
+ // arrange
+ localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+ // act
+ ControllableProcess controllable = new ControllableProcess(directory, processType,
+ localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+ // assert
+ assertThat(controllable.getDirectory()).isEqualTo(directory);
+ }
+
+ @Test
+ public void creationDeletesStatusRequestFileInDirectory() throws Exception {
+ // arrange
+ localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+ File file = new EmptyFileWriter(statusRequestFile).createNewFile();
+
+ // act
+ new ControllableProcess(directory, processType, localProcessLauncher, stopRequestFileWatchdog,
+ statusRequestFileWatchdog);
+
+ // assert
+ assertThat(file).doesNotExist();
+ }
+
+ @Test
+ public void creationDeletesStatusResponseFileInDirectory() throws Exception {
+ // arrange
+ localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+ File file = new EmptyFileWriter(statusFile).createNewFile();
+
+ // act
+ new ControllableProcess(directory, processType, localProcessLauncher, stopRequestFileWatchdog,
+ statusRequestFileWatchdog);
+
+ // assert
+ assertThat(file).doesNotExist();
+ }
+
+ @Test
+ public void creationDeletesStopRequestFileInDirectory() throws Exception {
+ // arrange
+ localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+ File file = new EmptyFileWriter(stopRequestFile).createNewFile();
+
+ // act
+ new ControllableProcess(directory, processType, localProcessLauncher, stopRequestFileWatchdog,
+ statusRequestFileWatchdog);
+
+ // assert
+ assertThat(file).doesNotExist();
+ }
+
+ @Test
+ public void getPidReturnsPid() throws Exception {
+ // arrange
+ localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+ // act
+ ControllableProcess controllable = new ControllableProcess(directory, processType,
+ localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+ // assert
+ assertThat(controllable.getPid()).isEqualTo(pid);
+ }
+
+ @Test
+ public void getPidFileExists() throws Exception {
+ // arrange
+ localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+ // act
+ ControllableProcess controllable = new ControllableProcess(directory, processType,
+ localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+ // assert
+ assertThat(controllable.getPidFile()).exists().hasContent(String.valueOf(pid));
+ }
+
+ @Test
+ public void stopsBothControlFileWatchdogs() throws Exception {
+ // arrange
+ ControlFileWatchdog stopRequestFileWatchdog = new ControlFileWatchdog(directory,
+ "stopRequestFile", mock(ControlRequestHandler.class), false);
+ ControlFileWatchdog statusRequestFileWatchdog = new ControlFileWatchdog(directory,
+ "statusRequestFile", mock(ControlRequestHandler.class), false);
+
+ stopRequestFileWatchdog = spy(stopRequestFileWatchdog);
+ statusRequestFileWatchdog = spy(statusRequestFileWatchdog);
+
+ localProcessLauncher = new LocalProcessLauncher(pidFile, false);
+
+ ControllableProcess controllable = new ControllableProcess(directory, processType,
+ localProcessLauncher, stopRequestFileWatchdog, statusRequestFileWatchdog);
+
+ // act
+ controllable.stop();
+
+ // assert
+ verify(stopRequestFileWatchdog).stop();
+ verify(statusRequestFileWatchdog).stop();
+ }
+
+ @Test
+ public void statusRequestFileIsDeletedAndStatusFileIsCreated() throws Exception {
+ // arrange
+ File statusRequestFile = new File(directory, processType.getStatusRequestFileName());
+ File statusFile = new File(directory, processType.getStatusFileName());
+
+ ServiceState mockServiceState = mock(ServiceState.class);
+ when(mockServiceState.toJson()).thenReturn("json");
+ ControlNotificationHandler mockHandler = mock(ControlNotificationHandler.class);
+ when(mockHandler.handleStatus()).thenReturn(mockServiceState);
+ new ControllableProcess(mockHandler, directory, processType, false);
+
+ // act
+ boolean created = statusRequestFile.createNewFile();
+
+ // assert
+ assertThat(created).isTrue();
+ await().atMost(2, MINUTES).until(() -> assertThat(statusRequestFile).doesNotExist());
+ assertThat(statusFile).exists();
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java
deleted file mode 100755
index 6ed12d4..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationJUnitTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static com.googlecode.catchexception.CatchException.*;
-import static org.awaitility.Awaitility.*;
-import static java.util.concurrent.TimeUnit.*;
-import static org.assertj.core.api.Assertions.*;
-import static org.mockito.Mockito.*;
-import static org.hamcrest.Matchers.*;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestName;
-
-import org.apache.geode.distributed.LocatorLauncher;
-import org.apache.geode.distributed.AbstractLauncher.Status;
-import org.apache.geode.distributed.LocatorLauncher.Builder;
-import org.apache.geode.distributed.LocatorLauncher.LocatorState;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * Integration tests for FileProcessController.
- */
-@Category(IntegrationTest.class)
-public class FileProcessControllerIntegrationJUnitTest {
-
- private ProcessType processType;
- private ExecutorService executor;
-
- @Rule
- public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
- @Rule
- public TestName testName = new TestName();
-
- @Before
- public void setUp() throws Exception {
- this.processType = ProcessType.LOCATOR;
- }
-
- @After
- public void tearDown() throws Exception {
- if (this.executor != null) {
- this.executor.shutdownNow();
- }
- }
-
- @Test
- public void statusShouldAwaitTimeoutWhileFileIsEmpty() throws Exception {
- // given: FileProcessController with empty pidFile
- int pid = ProcessUtils.identifyPid();
- File emptyPidFile = this.temporaryFolder.newFile(this.processType.getPidFileName());
- FileControllerParameters params = mock(FileControllerParameters.class);
- when(params.getPidFile()).thenReturn(emptyPidFile);
- when(params.getProcessId()).thenReturn(pid);
- when(params.getProcessType()).thenReturn(this.processType);
- when(params.getWorkingDirectory()).thenReturn(this.temporaryFolder.getRoot());
-
- FileProcessController controller = new FileProcessController(params, 1, 10, MILLISECONDS);
-
- // when
- verifyException(controller).status();
-
- // then: we expect TimeoutException to be thrown
- assertThat((Exception) caughtException()).isInstanceOf(TimeoutException.class)
- .hasMessageContaining("Timed out waiting for process to create").hasNoCause();
- }
-
- @Test
- public void statusShouldReturnJsonFromStatusFile() throws Exception {
- // given: FileProcessController with pidFile containing real pid
- int pid = ProcessUtils.identifyPid();
- File pidFile = this.temporaryFolder.newFile(this.processType.getPidFileName());
- writeToFile(pidFile, String.valueOf(pid));
-
- FileControllerParameters params = mock(FileControllerParameters.class);
- when(params.getPidFile()).thenReturn(pidFile);
- when(params.getProcessId()).thenReturn(pid);
- when(params.getProcessType()).thenReturn(this.processType);
- when(params.getWorkingDirectory()).thenReturn(this.temporaryFolder.getRoot());
-
- FileProcessController controller = new FileProcessController(params, pid, 1, MINUTES);
-
- // when: status is called in one thread and json is written to the file
- AtomicReference<String> status = new AtomicReference<String>();
- AtomicReference<Exception> exception = new AtomicReference<Exception>();
- this.executor = Executors.newSingleThreadExecutor();
- this.executor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- status.set(controller.status());
- } catch (Exception e) {
- exception.set(e);
- }
- }
- });
-
- // write status
- String statusJson = generateStatusJson();
- File statusFile = this.temporaryFolder.newFile(this.processType.getStatusFileName());
- writeToFile(statusFile, statusJson);
-
- // then: returned status should be the json in the file
- assertThat(exception.get()).isNull();
- with().pollInterval(10, MILLISECONDS).await().atMost(2, MINUTES).untilAtomic(status,
- equalTo(statusJson));
- assertThat(status.get()).isEqualTo(statusJson);
- System.out.println(statusJson);
- }
-
- private static void writeToFile(final File file, final String value) throws IOException {
- final FileWriter writer = new FileWriter(file);
- writer.write(value);
- writer.flush();
- writer.close();
- }
-
- private static String generateStatusJson() {
- Builder builder = new Builder();
- LocatorLauncher defaultLauncher = builder.build();
- Status status = Status.ONLINE;
- LocatorState locatorState = new LocatorState(defaultLauncher, status);
- return locatorState.toJson();
- }
-}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java
new file mode 100755
index 0000000..6eda29f
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerIntegrationTest.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static com.googlecode.catchexception.CatchException.caughtException;
+import static com.googlecode.catchexception.CatchException.verifyException;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.concurrent.TimeUnit.MINUTES;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.awaitility.Awaitility;
+import org.awaitility.core.ConditionFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.ErrorCollector;
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+
+import org.apache.geode.distributed.AbstractLauncher.Status;
+import org.apache.geode.distributed.LocatorLauncher;
+import org.apache.geode.distributed.LocatorLauncher.Builder;
+import org.apache.geode.distributed.LocatorLauncher.LocatorState;
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.internal.process.io.IntegerFileWriter;
+import org.apache.geode.internal.process.io.StringFileWriter;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+
+/**
+ * Integration tests for {@link FileProcessController}.
+ *
+ * <p>
+ * This test shows one of the more appropriate uses of ErrorCollector Rule -- catching any failed
+ * assertions in another thread that isn't the main JUnit thread.
+ */
+@Category(IntegrationTest.class)
+public class FileProcessControllerIntegrationTest {
+
+ private static final String STATUS_JSON = generateStatusJson();
+
+ private final AtomicReference<String> statusRef = new AtomicReference<>();
+
+ private File pidFile;
+ private File statusFile;
+ private File statusRequestFile;
+ private File stopRequestFile;
+ private int pid;
+ private FileControllerParameters params;
+ private ExecutorService executor;
+
+ @Rule
+ public ErrorCollector errorCollector = new ErrorCollector();
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Rule
+ public TestName testName = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ ProcessType processType = ProcessType.LOCATOR;
+ File directory = temporaryFolder.getRoot();
+ pidFile = new File(directory, processType.getPidFileName());
+ statusFile = new File(directory, processType.getStatusFileName());
+ statusRequestFile = new File(directory, processType.getStatusRequestFileName());
+ stopRequestFile = new File(directory, processType.getStopRequestFileName());
+ pid = ProcessUtils.identifyPid();
+
+ params = mock(FileControllerParameters.class);
+ when(params.getPidFile()).thenReturn(pidFile);
+ when(params.getProcessId()).thenReturn(pid);
+ when(params.getProcessType()).thenReturn(processType);
+ when(params.getDirectory()).thenReturn(temporaryFolder.getRoot());
+
+ executor = Executors.newSingleThreadExecutor();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ assertThat(executor.shutdownNow()).isEmpty();
+ }
+
+ @Test
+ public void statusShouldAwaitTimeoutWhileFileIsEmpty() throws Exception {
+ // given: FileProcessController with empty pidFile
+ FileProcessController controller = new FileProcessController(params, pid, 10, MILLISECONDS);
+
+ // when:
+ verifyException(controller).status();
+
+ // then: we expect TimeoutException to be thrown
+ assertThat((Exception) caughtException()).isInstanceOf(TimeoutException.class)
+ .hasMessageContaining("Timed out waiting for process to create").hasNoCause();
+ }
+
+ @Test
+ public void statusShouldReturnJsonFromStatusFile() throws Exception {
+ // given: FileProcessController with pidFile containing real pid
+ new IntegerFileWriter(pidFile).writeToFile(pid);
+ FileProcessController controller = new FileProcessController(params, pid, 2, MINUTES);
+
+ // when: status is called in one thread
+ executor.execute(() -> {
+ try {
+ statusRef.set(controller.status());
+ } catch (Exception e) {
+ errorCollector.addError(e);
+ }
+ });
+
+ // and: json is written to the status file
+ new StringFileWriter(statusFile).writeToFile(STATUS_JSON);
+
+ // then: returned status should be the json in the file
+ await().until(() -> assertThat(statusRef.get()).isEqualTo(STATUS_JSON));
+ }
+
+ /**
+ * This is a new test written for GEODE-3413: "Overhaul launcher tests and process tests."
+ * Unfortunately, it hangs so I have filed GEODE-3278. This test should be used to fix and verify
+ * that bug.
+ */
+ @Ignore("GEODE-3278: Empty status file causes status server and status locator to hang")
+ @Test
+ public void emptyStatusFileCausesStatusToHang() throws Exception {
+ // given: FileProcessController with pidFile containing real pid
+ new IntegerFileWriter(pidFile).writeToFile(pid);
+ FileProcessController controller = new FileProcessController(params, pid, 2, MINUTES);
+
+ // when: status is called in one thread
+ executor.execute(() -> {
+ try {
+ statusRef.set(controller.status());
+ } catch (Exception e) {
+ errorCollector.addError(e);
+ }
+ });
+
+ // and: json is written to the status file
+ new EmptyFileWriter(statusFile).createNewFile();
+
+ // then: returned status should be the json in the file
+ await().until(() -> assertThat(statusRef.get()).isEqualTo(STATUS_JSON));
+ }
+
+ @Test
+ public void stopCreatesStopRequestFile() throws Exception {
+ // arrange
+ FileProcessController controller = new FileProcessController(params, pid);
+ assertThat(stopRequestFile).doesNotExist();
+
+ // act
+ controller.stop();
+
+ // assert
+ assertThat(stopRequestFile).exists();
+ }
+
+ @Test
+ public void stop_withStopRequestFileExists_doesNotFail() throws Exception {
+ // arrange
+ FileProcessController controller = new FileProcessController(params, pid);
+ assertThat(stopRequestFile.createNewFile()).isTrue();
+
+ // act
+ controller.stop();
+
+ // assert
+ assertThat(stopRequestFile).exists();
+ }
+
+ @Test
+ public void status_withStatusRequestFileExists_doesNotFail() throws Exception {
+ // arrange
+ FileProcessController controller = new FileProcessController(params, pid);
+ assertThat(statusRequestFile.createNewFile()).isTrue();
+
+ // act
+ executor.execute(() -> {
+ try {
+ statusRef.set(controller.status());
+ } catch (Exception e) {
+ errorCollector.addError(e);
+ }
+ });
+
+ new StringFileWriter(statusFile).writeToFile(STATUS_JSON);
+
+ // assert
+ assertThat(statusRequestFile).exists();
+ }
+
+ @Test
+ public void statusCreatesStatusRequestFile() throws Exception {
+ // arrange
+ new IntegerFileWriter(pidFile).writeToFile(pid);
+ FileProcessController controller = new FileProcessController(params, pid, 2, MINUTES);
+
+ // act
+ executor.execute(() -> {
+ try {
+ assertThatThrownBy(() -> statusRef.set(controller.status()))
+ .isInstanceOf(InterruptedException.class);
+ } catch (Throwable t) {
+ errorCollector.addError(t);
+ }
+ });
+
+ // assert
+ await().until(() -> assertThat(statusRequestFile).exists());
+ }
+
+ private ConditionFactory await() {
+ return Awaitility.await().atMost(2, MINUTES);
+ }
+
+ private static String generateStatusJson() {
+ Builder builder = new Builder();
+ LocatorLauncher defaultLauncher = builder.build();
+ Status status = Status.ONLINE;
+ LocatorState locatorState = new LocatorState(defaultLauncher, status);
+ return locatorState.toJson();
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java
new file mode 100644
index 0000000..b742e1b
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/FileProcessControllerTest.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.geode.internal.process.FileProcessController.DEFAULT_STATUS_TIMEOUT_MILLIS;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.lang.AttachAPINotFoundException;
+import org.apache.geode.test.junit.categories.UnitTest;
+
+/**
+ * Unit tests for {@link FileProcessController}.
+ */
+@Category(UnitTest.class)
+public class FileProcessControllerTest {
+
+ private FileProcessController controller;
+ private FileControllerParameters mockParameters;
+ private int pid;
+ private long timeout;
+ private TimeUnit units;
+
+ @Before
+ public void before() throws Exception {
+ mockParameters = mock(FileControllerParameters.class);
+ pid = identifyPid();
+ timeout = 0;
+ units = SECONDS;
+
+ controller = new FileProcessController(mockParameters, pid, timeout, units);
+ }
+
+ @Test
+ public void pidLessThanOne_throwsIllegalArgumentException() throws Exception {
+ pid = 0;
+
+ assertThatThrownBy(() -> new FileProcessController(mockParameters, pid, timeout, units))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Invalid pid '" + pid + "' specified");
+ }
+
+ @Test
+ public void getProcessId_returnsPid() throws Exception {
+ assertThat(controller.getProcessId()).isEqualTo(pid);
+ }
+
+ @Test
+ public void checkPidSupport_throwsAttachAPINotFoundException() throws Exception {
+ assertThatThrownBy(() -> controller.checkPidSupport())
+ .isInstanceOf(AttachAPINotFoundException.class);
+ }
+
+ @Test
+ public void statusTimeoutMillis_defaultsToOneMinute() throws Exception {
+ FileProcessController controller = new FileProcessController(mockParameters, pid);
+
+ assertThat(controller.getStatusTimeoutMillis()).isEqualTo(DEFAULT_STATUS_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void timeoutLessThanZero_throwsIllegalArgumentException() throws Exception {
+ timeout = -1;
+
+ assertThatThrownBy(() -> new FileProcessController(mockParameters, pid, timeout, units))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Invalid timeout '" + timeout + "' specified");
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java
deleted file mode 100755
index b132647..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessControllerJUnitTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.lang.management.ManagementFactory;
-import java.util.Set;
-
-import javax.management.MBeanAttributeInfo;
-import javax.management.MBeanInfo;
-import javax.management.MBeanOperationInfo;
-import javax.management.MBeanServer;
-import javax.management.ObjectInstance;
-import javax.management.ObjectName;
-import javax.management.Query;
-import javax.management.QueryExp;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
-
-import org.apache.geode.internal.process.mbean.Process;
-import org.apache.geode.test.junit.categories.UnitTest;
-
-/**
- * Unit tests for LocalProcessController.
- *
- * @since GemFire 7.0
- */
-@Category(UnitTest.class)
-public class LocalProcessControllerJUnitTest {
-
- private MBeanServer server;
- private ObjectName objectName;
- private int pid;
-
- @Rule
- public TestName testName = new TestName();
-
- @Before
- public void setUp() throws Exception {
- pid = ProcessUtils.identifyPid();
- final Process process = new Process(pid, true);
-
- this.objectName = ObjectName
- .getInstance(getClass().getSimpleName() + ":testName=" + testName.getMethodName());
- this.server = ManagementFactory.getPlatformMBeanServer();
-
- final ObjectInstance instance = this.server.registerMBean(process, objectName);
- assertNotNull(instance);
- }
-
- @After
- public void tearDown() throws Exception {
- this.server.unregisterMBean(objectName);
- }
-
- @Test
- public void testProcessMBean() throws Exception {
- // validate basics of the ProcessMBean
- Set<ObjectName> mbeanNames = this.server.queryNames(objectName, null);
- assertFalse("Zero matching mbeans", mbeanNames.isEmpty());
- assertEquals(1, mbeanNames.size());
- final ObjectName name = mbeanNames.iterator().next();
-
- final MBeanInfo info = this.server.getMBeanInfo(name);
-
- final MBeanOperationInfo[] operInfo = info.getOperations();
- assertEquals(1, operInfo.length);
- assertEquals("stop", operInfo[0].getName());
-
- final MBeanAttributeInfo[] attrInfo = info.getAttributes();
- assertEquals(2, attrInfo.length);
- // The order of these attributes is indeterminate
- assertTrue("Pid".equals(attrInfo[0].getName()) || "Process".equals(attrInfo[0].getName()));
- assertTrue("Pid".equals(attrInfo[1].getName()) || "Process".equals(attrInfo[1].getName()));
- assertNotNull(this.server.getAttribute(name, "Pid"));
- assertNotNull(this.server.getAttribute(name, "Process"));
-
- assertEquals(pid, this.server.getAttribute(name, "Pid"));
- assertEquals(true, this.server.getAttribute(name, "Process"));
-
- // validate query using only Pid attribute
- QueryExp constraint = Query.eq(Query.attr("Pid"), Query.value(pid));
- mbeanNames = this.server.queryNames(objectName, constraint);
- assertFalse("Zero matching mbeans", mbeanNames.isEmpty());
-
- // validate query with wrong Pid finds nothing
- constraint = Query.eq(Query.attr("Pid"), Query.value(pid + 1));
- mbeanNames = this.server.queryNames(objectName, constraint);
- assertTrue("Found matching mbeans", mbeanNames.isEmpty());
-
- // validate query using both attributes
- constraint = Query.and(Query.eq(Query.attr("Process"), Query.value(true)),
- Query.eq(Query.attr("Pid"), Query.value(pid)));
- mbeanNames = this.server.queryNames(objectName, constraint);
- assertFalse("Zero matching mbeans", mbeanNames.isEmpty());
-
- // validate query with wrong attribute finds nothing
- constraint = Query.and(Query.eq(Query.attr("Process"), Query.value(false)),
- Query.eq(Query.attr("Pid"), Query.value(pid)));
- mbeanNames = this.server.queryNames(objectName, constraint);
- assertTrue("Found matching mbeans", mbeanNames.isEmpty());
- }
-}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java
deleted file mode 100755
index e1f3e6e..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDUnitTest.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.test.dunit.Host;
-import org.apache.geode.test.dunit.SerializableRunnable;
-import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
-import org.apache.geode.test.junit.categories.DistributedTest;
-
-/**
- * Multi-process tests for ProcessLauncher.
- *
- * @since GemFire 7.0
- */
-@Category(DistributedTest.class)
-@SuppressWarnings("serial")
-public class LocalProcessLauncherDUnitTest extends JUnit4DistributedTestCase {
-
- public LocalProcessLauncherDUnitTest() {
- super();
- }
-
- @Override
- public final void postSetUp() throws Exception {
- new File(getClass().getSimpleName()).mkdir();
- }
-
- @Test
- public void testExistingPidFileThrows() throws Exception {
- final File pidFile =
- new File(getClass().getSimpleName() + File.separator + "testExistingPidFileThrows.pid");
- final String absolutePath = pidFile.getAbsolutePath();
-
- assertFalse(pidFile.exists());
- new LocalProcessLauncher(pidFile, false);
- assertTrue(pidFile.exists());
-
- Host.getHost(0).getVM(0).invoke(
- new SerializableRunnable("LocalProcessLauncherDUnitTest#testExistingPidFileThrows") {
- @Override
- public void run() {
- try {
- new LocalProcessLauncher(new File(absolutePath), false);
- fail("Two processes both succeeded in creating " + pidFile);
- } catch (FileAlreadyExistsException e) {
- // passed
- } catch (IllegalStateException e) {
- throw new AssertionError(e);
- } catch (IOException e) {
- throw new AssertionError(e);
- } catch (PidUnavailableException e) {
- throw new AssertionError(e);
- }
- }
- });
- }
-
- @Test
- public void testForceReplacesExistingPidFile() throws Exception {
- final File pidFile = new File(
- getClass().getSimpleName() + File.separator + "testForceReplacesExistingPidFile.pid");
- final String absolutePath = pidFile.getAbsolutePath();
-
- assertFalse(pidFile.exists());
- final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
- assertTrue(pidFile.exists());
- assertNotNull(launcher);
- final int pid = launcher.getPid();
-
- Host.getHost(0).getVM(0).invoke(
- new SerializableRunnable("LocalProcessLauncherDUnitTest#testForceReplacesExistingPidFile") {
- @Override
- public void run() {
- try {
- final LocalProcessLauncher launcher =
- new LocalProcessLauncher(new File(absolutePath), true);
- assertNotSame(pid, launcher.getPid());
- assertFalse(pid == launcher.getPid());
-
- final FileReader fr = new FileReader(absolutePath);
- final BufferedReader br = new BufferedReader(fr);
- final int pidFromFile = Integer.parseInt(br.readLine());
- br.close();
-
- assertNotSame(pid, pidFromFile);
- assertFalse(pid == pidFromFile);
- assertEquals(launcher.getPid(), pidFromFile);
- } catch (IllegalStateException e) {
- throw new AssertionError(e);
- } catch (IOException e) {
- throw new AssertionError(e);
- } catch (FileAlreadyExistsException e) {
- throw new AssertionError(e);
- } catch (PidUnavailableException e) {
- throw new AssertionError(e);
- }
- }
- });
- }
-
- @Test
- public void testPidFileReadByOtherProcess() throws Exception {
- final File pidFile =
- new File(getClass().getSimpleName() + File.separator + "testPidFileReadByOtherProcess.pid");
- final String absolutePath = pidFile.getAbsolutePath();
-
- assertFalse(pidFile.exists());
- final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
- assertTrue(pidFile.exists());
- assertNotNull(launcher);
- final int pid = launcher.getPid();
-
- Host.getHost(0).getVM(0).invoke(
- new SerializableRunnable("LocalProcessLauncherDUnitTest#testPidFileReadByOtherProcess") {
- @Override
- public void run() {
- try {
- final FileReader fr = new FileReader(absolutePath);
- final BufferedReader br = new BufferedReader(fr);
- final int pidFromFile = Integer.parseInt(br.readLine());
- br.close();
- assertEquals(pid, pidFromFile);
- } catch (FileNotFoundException e) {
- throw new Error(e);
- } catch (IOException e) {
- throw new Error(e);
- }
- }
- });
- }
-}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java
new file mode 100755
index 0000000..deefa41
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherDistributedTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.apache.geode.test.dunit.Host.getHost;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import org.apache.geode.internal.process.io.IntegerFileReader;
+import org.apache.geode.test.dunit.DistributedTestCase;
+import org.apache.geode.test.dunit.VM;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
+import org.apache.geode.test.junit.rules.serializable.SerializableTestName;
+
+/**
+ * Two-process functional tests for {@link LocalProcessLauncher}.
+ *
+ * @since GemFire 7.0
+ */
+@Category(DistributedTest.class)
+public class LocalProcessLauncherDistributedTest extends DistributedTestCase {
+
+ private int pid;
+ private File pidFile;
+ private VM otherVM;
+
+ @Rule
+ public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();
+
+ @Rule
+ public SerializableTestName testName = new SerializableTestName();
+
+ @Before
+ public void before() throws Exception {
+ pid = identifyPid();
+ pidFile = new File(temporaryFolder.getRoot(), testName.getMethodName() + ".pid");
+ otherVM = getHost(0).getVM(0);
+ }
+
+ @Test
+ public void existingPidFileThrowsFileAlreadyExistsException() throws Exception {
+ // arrange
+ otherVM.invoke(this::createPidFile);
+ int firstPid = new IntegerFileReader(pidFile).readFromFile();
+
+ // act/assert
+ assertThatThrownBy(() -> new LocalProcessLauncher(pidFile, false))
+ .isInstanceOf(FileAlreadyExistsException.class);
+ assertThat(new IntegerFileReader(pidFile).readFromFile()).isEqualTo(firstPid);
+ }
+
+ @Test
+ public void forceReplacesExistingPidFile() throws Exception {
+ // arrange
+ otherVM.invoke(this::createPidFile);
+ int firstPid = new IntegerFileReader(pidFile).readFromFile();
+
+ // act
+ new LocalProcessLauncher(pidFile, true);
+
+ // assert
+ int secondPid = new IntegerFileReader(pidFile).readFromFile();
+ assertThat(secondPid).isNotEqualTo(firstPid).isEqualTo(pid);
+ }
+
+ private void createPidFile()
+ throws FileAlreadyExistsException, IOException, PidUnavailableException {
+ new LocalProcessLauncher(pidFile, false);
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java
new file mode 100644
index 0000000..2bcdeb3
--- /dev/null
+++ b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherIntegrationTest.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.internal.process;
+
+import static org.apache.geode.internal.process.LocalProcessLauncher.PROPERTY_IGNORE_IS_PID_ALIVE;
+import static org.apache.geode.internal.process.ProcessUtils.identifyPid;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.File;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.RestoreSystemProperties;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import org.apache.geode.internal.process.io.EmptyFileWriter;
+import org.apache.geode.internal.process.io.IntegerFileWriter;
+import org.apache.geode.internal.process.lang.AvailablePid;
+import org.apache.geode.test.junit.Retry;
+import org.apache.geode.test.junit.categories.IntegrationTest;
+import org.apache.geode.test.junit.rules.RetryRule;
+
+/**
+ * Functional integration tests for {@link LocalProcessLauncher}.
+ *
+ * <p>
+ * Tests involving fakePid use {@link RetryRule} because the fakePid may become used by a real
+ * process before the test executes.
+ */
+@Category(IntegrationTest.class)
+public class LocalProcessLauncherIntegrationTest {
+
+ private static final int PREFERRED_FAKE_PID = 42;
+
+ private File pidFile;
+ private int actualPid;
+ private int fakePid;
+
+ @Rule
+ public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties();
+
+ @Rule
+ public RetryRule retryRule = new RetryRule();
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Before
+ public void before() throws Exception {
+ pidFile = new File(temporaryFolder.getRoot(), "my.pid");
+ actualPid = identifyPid();
+ fakePid = new AvailablePid().findAvailablePid(PREFERRED_FAKE_PID);
+
+ assertThat(pidFile).doesNotExist();
+ }
+
+ @Test
+ public void createsPidFile() throws Exception {
+ // act
+ new LocalProcessLauncher(pidFile, false);
+
+ // assert
+ assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+ }
+
+ @Test
+ @Retry(3)
+ public void existingPidFileThrowsFileAlreadyExistsException() throws Exception {
+ // arrange
+ System.setProperty(PROPERTY_IGNORE_IS_PID_ALIVE, "true");
+ new IntegerFileWriter(pidFile).writeToFile(fakePid);
+
+ // act/assert
+ assertThatThrownBy(() -> new LocalProcessLauncher(pidFile, false))
+ .isInstanceOf(FileAlreadyExistsException.class);
+ }
+
+ @Test
+ public void overwritesPidFileIfForce() throws Exception {
+ // arrange
+ new IntegerFileWriter(pidFile).writeToFile(actualPid);
+
+ // act
+ new LocalProcessLauncher(pidFile, true);
+
+ // assert
+ assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+ }
+
+ @Test
+ @Retry(3)
+ public void overwritesPidFileIfOtherPidIsNotAlive() throws Exception {
+ // arrange
+ new IntegerFileWriter(pidFile).writeToFile(fakePid);
+
+ // act
+ new LocalProcessLauncher(pidFile, false);
+
+ // assert
+ assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+ }
+
+ @Test
+ public void overwritesEmptyPidFile() throws Exception {
+ // arrange
+ new EmptyFileWriter(pidFile).createNewFile();
+
+ // act
+ new LocalProcessLauncher(pidFile, false);
+
+ // assert
+ assertThat(pidFile).exists().hasContent(String.valueOf(actualPid));
+ }
+
+ @Test
+ public void getPidReturnsActualPid() throws Exception {
+ // arrange
+ LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
+
+ // act/assert
+ assertThat(launcher.getPid()).isEqualTo(actualPid);
+ }
+
+ @Test
+ public void getPidFileReturnsPidFile() throws Exception {
+ // arrange
+ LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
+
+ // act/assert
+ assertThat(launcher.getPidFile()).isEqualTo(pidFile);
+ }
+
+ @Test
+ public void closeDeletesPidFile() throws Exception {
+ // arrange
+ LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
+ assertThat(pidFile).exists();
+
+ // act
+ launcher.close();
+
+ // assert
+ assertThat(pidFile).doesNotExist();
+ }
+}
http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java
deleted file mode 100755
index 9393949..0000000
--- a/geode-core/src/test/java/org/apache/geode/internal/process/LocalProcessLauncherJUnitTest.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.apache.geode.internal.process;
-
-import static org.junit.Assert.*;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileWriter;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TemporaryFolder;
-import org.junit.rules.TestName;
-
-import org.apache.geode.internal.OSProcess;
-import org.apache.geode.test.junit.categories.IntegrationTest;
-
-/**
- * Unit tests for ProcessLauncher.
- *
- * @since GemFire 7.0
- */
-@Category(IntegrationTest.class)
-public class LocalProcessLauncherJUnitTest {
-
- @Rule
- public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
- @Rule
- public TestName testName = new TestName();
-
- private File pidFile;
-
- @Before
- public void setUp() throws Exception {
- this.pidFile = new File(this.temporaryFolder.getRoot(), testName.getMethodName() + ".pid");
- }
-
- @Test
- public void testPidAccuracy() throws PidUnavailableException {
- int pid = ProcessUtils.identifyPid();
- assertTrue(pid > 0);
- int osProcessPid = OSProcess.getId();
- if (osProcessPid > 0) {
- assertEquals(OSProcess.getId(), pid);
- } else {
- // not much to test if OSProcess native code is unusable
- }
- }
-
- @Test
- public void testPidFileIsCreated() throws Exception {
- assertFalse(pidFile.exists());
- new LocalProcessLauncher(pidFile, false);
- assertTrue(pidFile.exists());
- }
-
- @Test
- public void testPidFileContainsPid() throws Exception {
- final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
- assertNotNull(launcher);
- assertTrue(pidFile.exists());
-
- final FileReader fr = new FileReader(pidFile);
- final BufferedReader br = new BufferedReader(fr);
- final int pid = Integer.parseInt(br.readLine());
- br.close();
-
- assertTrue(pid > 0);
- assertEquals(launcher.getPid(), pid);
- assertEquals(ProcessUtils.identifyPid(), pid);
- }
-
- @Test
- public void testPidFileIsCleanedUp() throws Exception {
- final LocalProcessLauncher launcher = new LocalProcessLauncher(pidFile, false);
- assertTrue(pidFile.exists());
- launcher.close(); // TODO: launch an external JVM and then close it nicely
- assertFalse(pidFile.exists());
- }
-
- @Test
- public void testExistingPidFileThrows() throws Exception {
- assertTrue(pidFile.createNewFile());
- assertTrue(pidFile.exists());
-
- final FileWriter writer = new FileWriter(pidFile);
- // use a read pid that exists
- writer.write(String.valueOf(ProcessUtils.identifyPid()));
- writer.close();
-
- try {
- new LocalProcessLauncher(pidFile, false);
- fail("LocalProcessLauncher should have thrown FileAlreadyExistsException");
- } catch (FileAlreadyExistsException e) {
- // passed
- }
- }
-
- @Test
- public void testStalePidFileIsReplaced() throws Exception {
- assertTrue(pidFile.createNewFile());
- assertTrue(pidFile.exists());
-
- final FileWriter writer = new FileWriter(pidFile);
- writer.write(String.valueOf(Integer.MAX_VALUE));
- writer.close();
-
- try {
- new LocalProcessLauncher(pidFile, false);
- } catch (FileAlreadyExistsException e) {
- fail("LocalProcessLauncher should not have thrown FileAlreadyExistsException");
- }
-
- final FileReader fr = new FileReader(pidFile);
- final BufferedReader br = new BufferedReader(fr);
- final int pid = Integer.parseInt(br.readLine());
- br.close();
-
- assertTrue(pid > 0);
- assertEquals(ProcessUtils.identifyPid(), pid);
- }
-
- @Test
- public void testForceReplacesExistingPidFile() throws Exception {
- assertTrue("testForceReplacesExistingPidFile is broken if PID == Integer.MAX_VALUE",
- ProcessUtils.identifyPid() != Integer.MAX_VALUE);
-
- assertTrue(pidFile.createNewFile());
- assertTrue(pidFile.exists());
-
- final FileWriter writer = new FileWriter(pidFile);
- writer.write(String.valueOf(Integer.MAX_VALUE));
- writer.close();
-
- try {
- new LocalProcessLauncher(pidFile, true);
- } catch (FileAlreadyExistsException e) {
- fail("LocalProcessLauncher should not have thrown FileAlreadyExistsException");
- }
-
- final FileReader fr = new FileReader(pidFile);
- final BufferedReader br = new BufferedReader(fr);
- final int pid = Integer.parseInt(br.readLine());
- br.close();
-
- assertTrue(pid > 0);
- assertEquals(ProcessUtils.identifyPid(), pid);
- }
-
- @Test
- public void testPidUnavailableThrows() {
- final String name = "Name without PID";
- try {
- ProcessUtils.identifyPid(name);
- fail("PidUnavailableException should have been thrown for " + name);
- } catch (PidUnavailableException e) {
- // passed
- }
- }
-}