Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 2E36820049C for ; Fri, 11 Aug 2017 19:12:03 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 2C71C16D906; Fri, 11 Aug 2017 17:12:03 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id A971B16D8D8 for ; Fri, 11 Aug 2017 19:12:00 +0200 (CEST) Received: (qmail 79101 invoked by uid 500); 11 Aug 2017 17:11:59 -0000 Mailing-List: contact commits-help@geode.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.apache.org Delivered-To: mailing list commits@geode.apache.org Received: (qmail 79071 invoked by uid 99); 11 Aug 2017 17:11:59 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 11 Aug 2017 17:11:59 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 1E53AF321C; Fri, 11 Aug 2017 17:11:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: klund@apache.org To: commits@geode.apache.org Date: Fri, 11 Aug 2017 17:12:00 -0000 Message-Id: In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [02/14] geode git commit: GEODE-3413: overhaul launcher and process classes and tests archived-at: Fri, 11 Aug 2017 17:12:03 -0000 http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java new file mode 100644 index 0000000..000318c --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsIntegrationTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; + +import org.apache.geode.internal.util.StopWatch; +import org.apache.geode.test.junit.categories.IntegrationTest; + +/** + * Functional integration tests for {@link NativeProcessUtils}. + */ +@Category(IntegrationTest.class) +public class NativeProcessUtilsIntegrationTest { + + /** Max sleep timeout for {@link ProcessSleeps} */ + private static final int PROCESS_TIMEOUT_MILLIS = 10 * 60 * 1000; + + private static final String FILE_NAME = "pid.txt"; + + private NativeProcessUtils nativeProcessUtils; + private Process process; + private File pidFile; + private int pid; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void before() throws Exception { + File directory = temporaryFolder.getRoot(); + + List command = new ArrayList<>(); + command + .add(new File(new File(System.getProperty("java.home"), "bin"), "java").getCanonicalPath()); + command.add("-cp"); + command.add(System.getProperty("java.class.path")); + command.add(ProcessSleeps.class.getName()); + + process = new ProcessBuilder(command).directory(directory).start(); + assertThat(process.isAlive()).isTrue(); + + pidFile = new File(directory, FILE_NAME); + await().atMost(2, MINUTES).until(() -> assertThat(pidFile).exists()); + + pid = new PidFile(pidFile).readPid(); + assertThat(pid).isGreaterThan(0); + + nativeProcessUtils = new NativeProcessUtils(); + } + + @After + public void after() throws Exception { + process.destroyForcibly(); + } + + @Test + public void killProcessKillsOtherProcess() throws Exception { + // act + nativeProcessUtils.killProcess(pid); + + // assert + await().atMost(2, MINUTES).until(() -> assertThat(process.isAlive()).isFalse()); + } + + @Test + public void isProcessAliveReturnsTrueForLiveProcess() throws Exception { + // act/assert + assertThat(nativeProcessUtils.isProcessAlive(pid)).isTrue(); + } + + @Test + public void isProcessAliveReturnsFalseForDeadProcess() throws Exception { + // arrange + process.destroyForcibly(); + + // act/assert + await().atMost(2, MINUTES).until(() -> assertThat(process.isAlive()).isFalse()); + assertThat(nativeProcessUtils.isProcessAlive(pid)).isFalse(); + } + + /** + * Class with main that uses LocalProcessLauncher to create a PidFile and then sleeps. + */ + protected static class ProcessSleeps { + public static void main(final String... args) throws Exception { + new LocalProcessLauncher(new File(FILE_NAME), false); + StopWatch stopWatch = new StopWatch(true); + while (stopWatch.elapsedTimeMillis() < PROCESS_TIMEOUT_MILLIS) { + Thread.sleep(1000); + } + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java new file mode 100644 index 0000000..9c845b8 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/NativeProcessUtilsTest.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static org.apache.geode.internal.process.ProcessUtils.identifyPid; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.internal.process.lang.AvailablePid; +import org.apache.geode.test.junit.Retry; +import org.apache.geode.test.junit.categories.UnitTest; +import org.apache.geode.test.junit.rules.RetryRule; + +/** + * Unit tests for {@link NativeProcessUtils}. + * + *

+ * Tests involving fakePid use {@link RetryRule} because the fakePid may become used by a real + * process before the test executes. + */ +@Category(UnitTest.class) +public class NativeProcessUtilsTest { + + private static final int PREFERRED_FAKE_PID = 42; + + private int actualPid; + private int fakePid; + private NativeProcessUtils nativeProcessUtils; + + @Rule + public RetryRule retryRule = new RetryRule(); + + @Before + public void before() throws Exception { + actualPid = identifyPid(); + fakePid = new AvailablePid().findAvailablePid(PREFERRED_FAKE_PID); + nativeProcessUtils = new NativeProcessUtils(); + } + + @Test + public void isAttachApiAvailable_returnsFalse() throws Exception { + assertThat(nativeProcessUtils.isAttachApiAvailable()).isFalse(); + } + + @Test + public void isAvailable_returnsTrue() throws Exception { + assertThat(nativeProcessUtils.isAvailable()).isTrue(); + } + + @Test + public void isProcessAlive_livePid_returnsTrue() throws Exception { + assertThat(nativeProcessUtils.isProcessAlive(actualPid)).isTrue(); + } + + @Test + @Retry(3) + public void isProcessAlive_deadPid_returnsFalse() throws Exception { + assertThat(nativeProcessUtils.isProcessAlive(fakePid)).isFalse(); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java new file mode 100755 index 0000000..05b7cbc --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderIntegrationTest.java @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static org.apache.geode.internal.process.ProcessStreamReader.ReadingMode.NON_BLOCKING; + +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode; +import org.apache.geode.test.junit.categories.IntegrationTest; + +/** + * Functional integration tests for NonBlockingProcessStreamReader which was introduced to fix TRAC + * #51967: "GFSH start hangs on Windows" + * + * @see BlockingProcessStreamReaderIntegrationTest + * @see BlockingProcessStreamReaderWindowsTest + * + * @since GemFire 8.2 + */ +@Category(IntegrationTest.class) +public class NonBlockingProcessStreamReaderIntegrationTest + extends BaseProcessStreamReaderIntegrationTest { + + /** + * This test hangs on Windows if the implementation is blocking instead of non-blocking. Geode + * will always use the non-blocking implementation on Windows. If someone accidentally changes + * this, then the probably the first thing you'll notice is this test hanging. + */ + @Test + public void canCloseStreamsWhileProcessIsAlive() throws Exception { + // arrange + givenRunningProcessWithStreamReaders(ProcessSleeps.class); + + // act + process.getOutputStream().close(); + process.getErrorStream().close(); + process.getInputStream().close(); + + // assert + assertThatProcessIsAlive(process); + } + + @Test + public void canStopReadersWhileProcessIsAlive() throws Exception { + // arrange + givenRunningProcessWithStreamReaders(ProcessSleeps.class); + + // act + stdout.stop(); + stderr.stop(); + + // assert + assertThatProcessIsAlive(process); + } + + @Test + public void capturesStdoutWhileProcessIsAlive() throws Exception { + // arrange + givenStartedProcessWithStreamListeners(ProcessPrintsToStdout.class); + + // act + waitUntilProcessStops(); + + // assert + assertThatProcessAndReadersStopped(); + assertThatStdOutContainsExactly(ProcessPrintsToStdout.STDOUT); + assertThatStdErrContainsExactly(ProcessPrintsToStdout.STDERR); + } + + @Test + public void capturesStderrWhileProcessIsAlive() throws Exception { + // arrange + givenStartedProcessWithStreamListeners(ProcessPrintsToStderr.class); + + // act + waitUntilProcessStops(); + + // assert + assertThatProcessAndReadersStopped(); + assertThatStdOutContainsExactly(ProcessPrintsToStderr.STDOUT); + assertThatStdErrContainsExactly(ProcessPrintsToStderr.STDERR); + } + + @Test + public void capturesBothWhileProcessIsAlive() throws Exception { + // arrange + givenStartedProcessWithStreamListeners(ProcessPrintsToBoth.class); + + // act + waitUntilProcessStops(); + + // assert + assertThatProcessAndReadersStopped(); + assertThatStdOutContainsExactly(ProcessPrintsToBoth.STDOUT); + assertThatStdErrContainsExactly(ProcessPrintsToBoth.STDERR); + } + + @Test + public void capturesStderrWhenProcessFailsDuringStart() throws Exception { + // arrange + givenStartedProcessWithStreamListeners(ProcessThrowsError.class); + + // act + waitUntilProcessStops(); + + // assert + assertThatProcessAndReadersStoppedWithExitValue(1); + assertThatStdOutContainsExactly(ProcessThrowsError.STDOUT); + assertThatStdErrContains(ProcessThrowsError.ERROR_MSG); + } + + @Override + protected ReadingMode getReadingMode() { + return NON_BLOCKING; + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java deleted file mode 100755 index 105e7f0..0000000 --- a/geode-core/src/test/java/org/apache/geode/internal/process/NonBlockingProcessStreamReaderJUnitTest.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.process; - -import static org.junit.Assert.*; - -import java.util.concurrent.Callable; - -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.internal.process.ProcessStreamReader.InputListener; -import org.apache.geode.internal.process.ProcessStreamReader.ReadingMode; -import org.apache.geode.test.junit.categories.IntegrationTest; - -/** - * Tests NonBlockingProcessStreamReader which was introduced to fix TRAC bug #51967. - * - * None of the tests should be skipped or hang on Windows. - * - * @since GemFire 8.2 - */ -@Category(IntegrationTest.class) -public class NonBlockingProcessStreamReaderJUnitTest extends ProcessStreamReaderTestCase { - - @Test - public void canCloseStreamsWhileProcessIsAlive() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start(); - - this.stderr = new ProcessStreamReader.Builder(this.process) - .inputStream(this.process.getErrorStream()).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stdout = new ProcessStreamReader.Builder(this.process) - .inputStream(this.process.getInputStream()).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stderr.start(); - this.stdout.start(); - - assertIsAlive(this.process); - - assertEventuallyIsRunning(this.stderr); - assertEventuallyIsRunning(this.stdout); - - this.process.getErrorStream().close(); - this.process.getOutputStream().close(); - this.process.getInputStream().close(); - - this.stderr.stop(); - this.stdout.stop(); - - assertIsAlive(this.process); - - this.process.destroy(); - } - - @Test - public void canStopReadersWhileProcessIsAlive() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start(); - - this.stderr = new ProcessStreamReader.Builder(this.process) - .inputStream(this.process.getErrorStream()).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stdout = new ProcessStreamReader.Builder(this.process) - .inputStream(this.process.getInputStream()).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stderr.start(); - this.stdout.start(); - - assertIsAlive(this.process); - - assertEventuallyIsRunning(this.stderr); - assertEventuallyIsRunning(this.stdout); - - this.stderr.stop(); - this.stdout.stop(); - - this.process.getErrorStream().close(); - this.process.getOutputStream().close(); - this.process.getInputStream().close(); - - assertIsAlive(this.process); - - this.process.destroy(); - } - - @Test - public void capturesStdoutWhileProcessIsAlive() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStdout.class)).start(); - - final StringBuffer stderrBuffer = new StringBuffer(); - InputListener stderrListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stderrBuffer.append(line); - } - }; - - final StringBuffer stdoutBuffer = new StringBuffer(); - InputListener stdoutListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stdoutBuffer.append(line); - } - }; - - this.stderr = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream()) - .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stdout = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream()) - .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stderr.start(); - this.stdout.start(); - - // wait for process to die - assertEventuallyFalse("Process never died", new Callable() { - @Override - public Boolean call() throws Exception { - return ProcessUtils.isProcessAlive(process); - } - }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL); - - final int exitValue = this.process.exitValue(); - assertEquals(0, exitValue); - - this.stderr.join(READER_JOIN_TIMEOUT); - assertFalse(this.stderr.isRunning()); - - this.stdout.join(READER_JOIN_TIMEOUT); - assertFalse(this.stdout.isRunning()); - - // System.out.println("Stopping ProcessStreamReader"); - this.stderr.stop(); - this.stdout.stop(); - - // System.out.println("stderr=\n" + stderrBuffer.toString()); - assertEquals("", stderrBuffer.toString()); - - // System.out.println("stdout=\n" + stdoutBuffer.toString()); - StringBuilder sb = new StringBuilder().append(ProcessPrintsToStdout.LINES[0]) - .append(ProcessPrintsToStdout.LINES[1]).append(ProcessPrintsToStdout.LINES[2]); - assertEquals(sb.toString(), stdoutBuffer.toString()); - - // System.out.println("Closing streams"); - this.process.getErrorStream().close(); - this.process.getInputStream().close(); - - this.process.destroy(); - } - - @Test - public void capturesStderrWhileProcessIsAlive() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToStderr.class)).start(); - - final StringBuffer stderrBuffer = new StringBuffer(); - InputListener stderrListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stderrBuffer.append(line); - } - }; - - final StringBuffer stdoutBuffer = new StringBuffer(); - InputListener stdoutListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stdoutBuffer.append(line); - } - }; - - this.stderr = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream()) - .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stdout = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream()) - .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stderr.start(); - this.stdout.start(); - - // wait for process to die - assertEventuallyFalse("Process never died", new Callable() { - @Override - public Boolean call() throws Exception { - return ProcessUtils.isProcessAlive(process); - } - }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL); - - final int exitValue = this.process.exitValue(); - assertEquals(0, exitValue); - - this.stderr.join(READER_JOIN_TIMEOUT); - assertFalse(this.stderr.isRunning()); - - this.stdout.join(READER_JOIN_TIMEOUT); - assertFalse(this.stdout.isRunning()); - - // System.out.println("Stopping ProcessStreamReader"); - this.stderr.stop(); - this.stdout.stop(); - - // System.out.println("stderr=\n" + stderrBuffer.toString()); - StringBuilder sb = new StringBuilder().append(ProcessPrintsToStderr.LINES[0]) - .append(ProcessPrintsToStderr.LINES[1]).append(ProcessPrintsToStderr.LINES[2]); - assertEquals(sb.toString(), stderrBuffer.toString()); - - // System.out.println("stdout=\n" + stdoutBuffer.toString()); - assertEquals("", stdoutBuffer.toString()); - - // System.out.println("Closing streams"); - this.process.getErrorStream().close(); - this.process.getInputStream().close(); - - this.process.destroy(); - } - - @Test - public void capturesBothWhileProcessIsAlive() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessPrintsToBoth.class)).start(); - - final StringBuffer stderrBuffer = new StringBuffer(); - InputListener stderrListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stderrBuffer.append(line); - } - }; - - final StringBuffer stdoutBuffer = new StringBuffer(); - InputListener stdoutListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stdoutBuffer.append(line); - } - }; - - this.stderr = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream()) - .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stdout = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream()) - .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stderr.start(); - this.stdout.start(); - - // wait for process to die - assertEventuallyFalse("Process never died", new Callable() { - @Override - public Boolean call() throws Exception { - return ProcessUtils.isProcessAlive(process); - } - }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL); - - final int exitValue = this.process.exitValue(); - assertEquals(0, exitValue); - - this.stderr.join(READER_JOIN_TIMEOUT); - assertFalse(this.stderr.isRunning()); - - this.stdout.join(READER_JOIN_TIMEOUT); - assertFalse(this.stdout.isRunning()); - - // System.out.println("Stopping ProcessStreamReader"); - this.stderr.stop(); - this.stdout.stop(); - - // System.out.println("stderr=\n" + stderrBuffer.toString()); - StringBuilder sb = new StringBuilder().append(ProcessPrintsToBoth.ERR_LINES[0]) - .append(ProcessPrintsToBoth.ERR_LINES[1]).append(ProcessPrintsToBoth.ERR_LINES[2]); - assertEquals(sb.toString(), stderrBuffer.toString()); - - // System.out.println("stdout=\n" + stdoutBuffer.toString()); - sb = new StringBuilder().append(ProcessPrintsToBoth.OUT_LINES[0]) - .append(ProcessPrintsToBoth.OUT_LINES[1]).append(ProcessPrintsToBoth.OUT_LINES[2]); - assertEquals(sb.toString(), stdoutBuffer.toString()); - - // System.out.println("Closing streams"); - this.process.getErrorStream().close(); - this.process.getInputStream().close(); - - this.process.destroy(); - } - - @Test - public void capturesStderrWhenProcessFailsDuringStart() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessThrowsError.class)).start(); - - final StringBuffer stderrBuffer = new StringBuffer(); - InputListener stderrListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stderrBuffer.append(line); - } - }; - - final StringBuffer stdoutBuffer = new StringBuffer(); - InputListener stdoutListener = new InputListener() { - @Override - public void notifyInputLine(String line) { - stdoutBuffer.append(line); - } - }; - - this.stderr = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getErrorStream()) - .inputListener(stderrListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stdout = - new ProcessStreamReader.Builder(this.process).inputStream(this.process.getInputStream()) - .inputListener(stdoutListener).readingMode(ReadingMode.NON_BLOCKING).build(); - - this.stderr.start(); - this.stdout.start(); - - // wait for process to die - assertEventuallyFalse("Process never died", new Callable() { - @Override - public Boolean call() throws Exception { - return ProcessUtils.isProcessAlive(process); - } - }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL); - - final int exitValue = this.process.exitValue(); - assertNotEquals(0, exitValue); - - this.stderr.join(READER_JOIN_TIMEOUT); - assertFalse(this.stderr.isRunning()); - - this.stdout.join(READER_JOIN_TIMEOUT); - assertFalse(this.stdout.isRunning()); - - // System.out.println("Stopping ProcessStreamReader"); - this.stderr.stop(); - this.stdout.stop(); - - // System.out.println("stderr=\n" + stderrBuffer.toString()); - assertTrue(stderrBuffer.toString() + " does not contain " + ProcessThrowsError.ERROR_MSG, - stderrBuffer.toString().contains(ProcessThrowsError.ERROR_MSG)); - - // System.out.println("stdout=\n" + stdoutBuffer.toString()); - - // System.out.println("Closing streams"); - this.process.getErrorStream().close(); - this.process.getInputStream().close(); - - this.process.destroy(); - } -} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java new file mode 100755 index 0000000..584f185 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/PidFileIntegrationTest.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static org.apache.geode.internal.process.ProcessUtils.identifyPid; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; + +import org.apache.geode.internal.process.io.IntegerFileWriter; +import org.apache.geode.internal.process.lang.AvailablePid; +import org.apache.geode.test.junit.categories.IntegrationTest; + +/** + * Functional integration tests for {@link PidFile}. + * + * @since GemFire 8.2 + */ +@Category(IntegrationTest.class) +public class PidFileIntegrationTest { + + private File directory; + private File pidFile; + private String pidFileName; + private ExecutorService futures; + private int pid; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void before() throws Exception { + directory = temporaryFolder.getRoot(); + pidFile = new File(directory, "pid.txt"); + pidFileName = pidFile.getName(); + futures = Executors.newFixedThreadPool(2); + pid = identifyPid(); + } + + @After + public void after() { + assertThat(this.futures.shutdownNow()).isEmpty(); + } + + @Test + public void readsIntFromFile() throws Exception { + // arrange + String value = "42"; + new IntegerFileWriter(pidFile).writeToFile(value); + + // act + int readValue = new PidFile(pidFile).readPid(); + + // assert + assertThat(readValue).isEqualTo(Integer.parseInt(value)); + } + + @Test + public void readingEmptyFileThrowsIllegalArgumentException() throws Exception { + // arrange + new IntegerFileWriter(pidFile).writeToFile(""); + + // act/assert + assertThatThrownBy(() -> new PidFile(pidFile).readPid()) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void readingFileWithNonIntegerThrowsIllegalArgumentException() throws Exception { + // arrange + String value = "forty two"; + new IntegerFileWriter(pidFile).writeToFile(value); + + // act/assert + assertThatThrownBy(() -> new PidFile(pidFile).readPid()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid pid '" + value + "' found"); + } + + @Test + public void readingFileWithNegativeIntegerThrowsIllegalArgumentException() throws Exception { + // arrange + String value = "-42"; + new IntegerFileWriter(pidFile).writeToFile(value); + + // act/assert + assertThatThrownBy(() -> new PidFile(pidFile).readPid()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid pid '" + value + "' found"); + } + + @Test + public void readingNullFileThrowsNullPointerException() throws Exception { + // arrange + pidFile = null; + + // act/assert + assertThatThrownBy(() -> new PidFile(pidFile).readPid()) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void findsCorrectFileByName() throws Exception { + // arrange + new IntegerFileWriter(pidFile).writeToFile(pid); + int[] pids = new AvailablePid().findAvailablePids(4); + for (int i = 1; i <= pids.length; i++) { + new IntegerFileWriter(new File(directory, "pid" + i + ".txt")).writeToFile(pids[i - 1]); + } + assertThat(directory.listFiles()).hasSize(pids.length + 1); + + // act + PidFile namedPidFile = new PidFile(directory, pidFile.getName()); + + // assert + assertThat(namedPidFile.getFile()).hasContent(String.valueOf(pid)); + assertThat(namedPidFile.readPid()).isEqualTo(pid); + } + + @Test + public void missingFileInEmptyDirectoryThrowsFileNotFoundException() throws Exception { + // arrange + assertThat(pidFile).doesNotExist(); + + // act/assert + assertThatThrownBy(() -> new PidFile(directory, pidFileName).readPid()) + .isInstanceOf(FileNotFoundException.class).hasMessage( + "Unable to find PID file '" + pidFileName + "' in directory '" + directory + "'"); + } + + @Test + public void fileForDirectoryThrowsIllegalArgumentException() throws Exception { + // arrange + File directoryIsFile = temporaryFolder.newFile("my.file"); + + // act/assert + assertThatThrownBy(() -> new PidFile(directoryIsFile, pidFileName).readPid()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Nonexistent directory '" + directoryIsFile + "' specified"); + } + + @Test + public void missingFileThrowsFileNotFoundException() throws Exception { + // act/assert + assertThatThrownBy(() -> new PidFile(pidFile).readPid()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Nonexistent file '" + pidFile + "' specified"); + } + + @Test + public void missingFileInFullDirectoryThrowsFileNotFoundException() throws Exception { + // arrange + int[] pids = new AvailablePid().findAvailablePids(4); + for (int i = 1; i <= pids.length; i++) { + new IntegerFileWriter(new File(directory, "pid" + i + ".txt")).writeToFile(pids[i - 1]); + } + assertThat(directory.listFiles()).hasSameSizeAs(pids); + + // act/assert + assertThatThrownBy(() -> new PidFile(directory, pidFileName).readPid()) + .isInstanceOf(FileNotFoundException.class).hasMessage( + "Unable to find PID file '" + pidFileName + "' in directory '" + directory + "'"); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java deleted file mode 100755 index 0ca73c4..0000000 --- a/geode-core/src/test/java/org/apache/geode/internal/process/PidFileJUnitTest.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.process; - -import static org.junit.Assert.*; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; -import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.jmock.Mockery; -import org.jmock.lib.concurrent.Synchroniser; -import org.jmock.lib.legacy.ClassImposteriser; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; - -import org.apache.geode.internal.util.StopWatch; -import org.apache.geode.test.junit.categories.IntegrationTest; -import org.apache.geode.test.junit.rules.ExpectedTimeoutRule; - -/** - * Unit tests the PidFile class. - * - * @since GemFire 8.2 - */ -@Category(IntegrationTest.class) -public class PidFileJUnitTest { - - @Rule - public TemporaryFolder testFolder = new TemporaryFolder(); - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Rule - public ExpectedTimeoutRule timeout = ExpectedTimeoutRule.none(); - - protected Mockery mockContext; - private ExecutorService futures; - - @Before - public void before() { - mockContext = new Mockery() { - { - setImposteriser(ClassImposteriser.INSTANCE); - setThreadingPolicy(new Synchroniser()); - } - }; - this.futures = Executors.newFixedThreadPool(2); - } - - @After - public void after() { - mockContext.assertIsSatisfied(); - assertTrue(this.futures.shutdownNow().isEmpty()); - } - - @Test - public void readsIntFromFile() throws Exception { - final File file = testFolder.newFile("my.pid"); - final String value = "42"; - writeToFile(file, value); - - final int readValue = new PidFile(file).readPid(); - assertEquals(Integer.parseInt(value), readValue); - } - - @Test - public void readingEmptyFileThrowsIllegalArgumentException() throws Exception { - final File file = testFolder.newFile("my.pid"); - - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Invalid pid 'null' found"); - - new PidFile(file).readPid(); - } - - @Test - public void readingFileWithNonIntegerThrowsIllegalArgumentException() throws Exception { - final File file = testFolder.newFile("my.pid"); - final String value = "fortytwo"; - writeToFile(file, value); - - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Invalid pid '" + value + "' found"); - - new PidFile(file).readPid(); - } - - @Test - public void readingFileWithNegativeIntegerThrowsIllegalArgumentException() throws Exception { - final File file = testFolder.newFile("my.pid"); - final String value = "-42"; - writeToFile(file, value); - - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Invalid pid '" + value + "' found"); - - new PidFile(file).readPid(); - } - - @Test - public void readingNullFileThrowsNullPointerException() throws Exception { - final File file = null; - - thrown.expect(NullPointerException.class); - - new PidFile(file).readPid(); - } - - @Test - public void timesOutReadingFromEmptyFile() throws Exception { - final File file = testFolder.newFile("my.pid"); - - timeout.expect(TimeoutException.class); - timeout.expectMessage("Invalid pid 'null' found"); - timeout.expectMinimumDuration(1000); - timeout.expectMaximumDuration(10000); - timeout.expectTimeUnit(TimeUnit.MILLISECONDS); - - new PidFile(file).readPid(1500, TimeUnit.MILLISECONDS); - } - - @Test - public void readsIntBeforeTimeout() throws Exception { - final int AWAIT_LATCH_TIMEOUT_MILLIS = 10 * 1000; - final int OPEN_LATCH_DELAY_MILLIS = 2 * 1000; - final int FUTURE_GET_TIMEOUT_MILLIS = 2 * 1000; - final int READ_PID_TIMEOUT_MILLIS = 2 * OPEN_LATCH_DELAY_MILLIS; - - final File file = testFolder.newFile("my.pid"); - final FileWriter writer = new FileWriter(file); - - final CountDownLatch writePidLatch = new CountDownLatch(1); - final String value = "42"; - - // start Future to write the pid later but before timeout - Future futureWritePid = this.futures.submit(new Callable() { - @Override - public Boolean call() throws Exception { - writePidLatch.await(AWAIT_LATCH_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - writeToFile(file, value); - return true; - } - }); - - // start Future to sleep and release the delay - Future futureOpenLatch = this.futures.submit(new Callable() { - @Override - public Boolean call() throws Exception { - Thread.sleep(OPEN_LATCH_DELAY_MILLIS); - writePidLatch.countDown(); - return true; - } - }); - - StopWatch stopWatch = new StopWatch(true); - final int readValue = new PidFile(file).readPid(READ_PID_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - assertEquals(Integer.parseInt(value), readValue); - - long duration = stopWatch.elapsedTimeMillis(); - assertTrue(duration > OPEN_LATCH_DELAY_MILLIS); - assertTrue(duration < READ_PID_TIMEOUT_MILLIS); - - assertEquals(0, writePidLatch.getCount()); - assertTrue(futureOpenLatch.get(FUTURE_GET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); - assertTrue(futureWritePid.get(FUTURE_GET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)); - } - - @Test - public void findsCorrectFile() throws Exception { - final File directory = testFolder.getRoot(); - - final String fileNames[] = new String[] {"other.txt", "my.txt", "a.log", "b.log"}; - for (String fileName : fileNames) { - testFolder.newFile(fileName); - } - - final int pidValue = 42; - final File file = testFolder.newFile("my.pid"); - writeToFile(file, String.valueOf(pidValue)); - - final File other = testFolder.newFile("other.pid"); - writeToFile(other, "43"); - - final File[] files = directory.listFiles(); - assertEquals(fileNames.length + 2, files.length); - - PidFile pidFile = new PidFile(directory, file.getName()); - assertEquals(file, pidFile.getFile()); - - int value = pidFile.readPid(); - assertEquals(pidValue, value); - } - - @Test - public void missingFileInEmptyDirectoryThrowsFileNotFoundException() throws Exception { - final File directory = testFolder.getRoot(); - - final String pidFileName = "my.pid"; - - thrown.expect(FileNotFoundException.class); - thrown.expectMessage("Unable to find PID file '" + pidFileName + "' in directory " + directory); - - new PidFile(directory, pidFileName); - } - - @Test - public void missingFileThrowsFileNotFoundException() throws Exception { - final String pidFileName = "my.pid"; - - final File directory = testFolder.getRoot(); - final File file = new File(directory, pidFileName); - - thrown.expect(FileNotFoundException.class); - thrown.expectMessage("Unable to find PID file '" + file + "'"); - - new PidFile(file); - } - - @Test - public void missingFileInFullDirectoryThrowsFileNotFoundException() throws Exception { - final File directory = testFolder.getRoot(); - - final String fileNames[] = new String[] {"other.txt", "my.txt", "a.log", "b.log"}; - for (String fileName : fileNames) { - testFolder.newFile(fileName); - } - - final File other = testFolder.newFile("other.pid"); - writeToFile(other, "43"); - - final File[] files = directory.listFiles(); - assertEquals(fileNames.length + 1, files.length); - - final String pidFileName = "my.pid"; - - thrown.expect(FileNotFoundException.class); - thrown.expectMessage("Unable to find PID file '" + pidFileName + "' in directory " + directory); - - new PidFile(directory, pidFileName); - } - - private void writeToFile(final File file, String value) throws IOException { - final FileWriter writer = new FileWriter(file); - writer.write(value); - writer.flush(); - writer.close(); - } -} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java new file mode 100644 index 0000000..aafa260 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryIntegrationTest.java @@ -0,0 +1,135 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static org.apache.geode.internal.process.ProcessUtils.identifyPid; +import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import java.io.File; +import java.io.FileNotFoundException; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; + +import org.apache.geode.internal.process.io.IntegerFileWriter; +import org.apache.geode.test.junit.categories.IntegrationTest; + +/** + * Functional integration tests for {@link ProcessControllerFactory}. + */ +@Category(IntegrationTest.class) +public class ProcessControllerFactoryIntegrationTest { + + private ProcessControllerFactory factory; + private ProcessControllerParameters parameters; + private File directory; + private File pidFile; + private String pidFileName; + private int pid; + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Before + public void before() throws Exception { + factory = new ProcessControllerFactory(); + parameters = mock(ProcessControllerParameters.class); + directory = temporaryFolder.getRoot(); + pidFile = new File(directory, "pid.txt"); + pidFileName = pidFile.getName(); + pid = identifyPid(); + + assertThat(pidFile).doesNotExist(); + assertThat(isProcessAlive(pid)).isTrue(); + } + + @Test + public void createProcessController_withoutPidFile_throwsFileNotFoundException() + throws Exception { + // act/assert + assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName)) + .isInstanceOf(FileNotFoundException.class); + } + + @Test + public void createProcessController_returnsMBeanProcessController() throws Exception { + // arrange + new IntegerFileWriter(pidFile).writeToFile(pid); + + // act + ProcessController controller = + factory.createProcessController(parameters, directory, pidFileName); + + // assert + assertThat(controller).isInstanceOf(MBeanProcessController.class); + } + + @Test + public void createProcessController_withoutAttachAPI_returnsFileProcessController() + throws Exception { + // arrange + new IntegerFileWriter(pidFile).writeToFile(pid); + System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true"); + factory = new ProcessControllerFactory(); + + // act + ProcessController controller = + factory.createProcessController(parameters, directory, pidFileName); + + // assert + assertThat(controller).isInstanceOf(FileProcessController.class); + } + + @Test + public void createProcessController_nullParameters_throwsNullPointerException() throws Exception { + // arrange + parameters = null; + + // act/assert + assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void createProcessController_nullDirectory_throwsNullPointerException() throws Exception { + // arrange + directory = null; + + // act/assert + assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void createProcessController_nullPidFileName_throwsNullPointerException() + throws Exception { + // arrange + pidFileName = null; + + // act/assert + assertThatThrownBy(() -> factory.createProcessController(parameters, directory, pidFileName)) + .isInstanceOf(IllegalArgumentException.class); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java deleted file mode 100755 index b9c8030..0000000 --- a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryJUnitTest.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.process; - -import static org.junit.Assert.*; - -import java.io.File; - -import javax.management.ObjectName; - -import org.junit.After; -import org.junit.Test; -import org.junit.experimental.categories.Category; - -import org.apache.geode.test.junit.categories.UnitTest; - -/** - * @since GemFire 8.0 - */ -@Category(UnitTest.class) -public class ProcessControllerFactoryJUnitTest { - - @After - public void tearDown() throws Exception { - enableAttachApi(); - } - - @Test - public void testIsAttachAPIFound() throws Exception { - validateProcessControllerFactory(true); - disableAttachApi(); - validateProcessControllerFactory(false); - enableAttachApi(); - validateProcessControllerFactory(true); - } - - private void validateProcessControllerFactory(boolean isAttachAPIFound) throws Exception { - final ProcessControllerFactory factory = new ProcessControllerFactory(); - assertEquals(isAttachAPIFound, factory.isAttachAPIFound()); - if (isAttachAPIFound) { - final ProcessControllerParameters parms = new NullMBeanControllerParameters(); - final ProcessController controller = - factory.createProcessController(parms, ProcessUtils.identifyPid()); - assertTrue(controller instanceof MBeanProcessController); - } else { - final ProcessControllerParameters parms = new NullFileControllerParameters(); - final ProcessController controller = - factory.createProcessController(parms, ProcessUtils.identifyPid()); - assertTrue(controller instanceof FileProcessController); - } - } - - private static void disableAttachApi() { - System.setProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API, "true"); - } - - private static void enableAttachApi() { - System.clearProperty(ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API); - } - - private static class NullMBeanControllerParameters implements ProcessControllerParameters { - @Override - public int getProcessId() { - return 0; - } - - @Override - public ProcessType getProcessType() { - return null; - } - - @Override - public ObjectName getNamePattern() { - return null; - } - - @Override - public String getPidAttribute() { - return null; - } - - @Override - public String getStatusMethod() { - return null; - } - - @Override - public String getStopMethod() { - return null; - } - - @Override - public String[] getAttributes() { - return null; - } - - @Override - public Object[] getValues() { - return null; - } - - @Override - public File getPidFile() { - throw new UnsupportedOperationException("Not implemented by NullMBeanControllerParameters"); - } - - @Override - public File getWorkingDirectory() { - throw new UnsupportedOperationException("Not implemented by NullMBeanControllerParameters"); - } - } - - private static class NullFileControllerParameters implements ProcessControllerParameters { - @Override - public int getProcessId() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public ProcessType getProcessType() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public ObjectName getNamePattern() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public String getPidAttribute() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public String getStatusMethod() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public String getStopMethod() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public String[] getAttributes() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public Object[] getValues() { - throw new UnsupportedOperationException("Not implemented by NullFileControllerParameters"); - } - - @Override - public File getPidFile() { - return null; - } - - @Override - public File getWorkingDirectory() { - return null; - } - } -} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java new file mode 100755 index 0000000..55f5d58 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessControllerFactoryTest.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static org.apache.geode.internal.process.ProcessControllerFactory.PROPERTY_DISABLE_ATTACH_API; +import static org.apache.geode.internal.process.ProcessUtils.identifyPid; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.UnitTest; + +/** + * Unit tests for {@link ProcessControllerFactory}. + * + * @since GemFire 8.0 + */ +@Category(UnitTest.class) +public class ProcessControllerFactoryTest { + + private ProcessControllerFactory factory; + private ProcessControllerParameters parameters; + private int pid; + + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + + @Before + public void before() throws Exception { + factory = new ProcessControllerFactory(); + parameters = mock(ProcessControllerParameters.class); + pid = identifyPid(); + } + + @Test + public void isAttachAPIFound_withAttachAPI_returnsTrue() throws Exception { + // act/assert + assertThat(factory.isAttachAPIFound()).isTrue(); + } + + @Test + public void isAttachAPIFound_withoutAttachAPI_returnsFalse() throws Exception { + // arrange + System.setProperty(PROPERTY_DISABLE_ATTACH_API, "true"); + factory = new ProcessControllerFactory(); + + // act/assert + assertThat(factory.isAttachAPIFound()).isFalse(); + } + + @Test + public void createProcessController_withAttachAPI_returnsMBeanProcessController() + throws Exception { + // act + ProcessController controller = factory.createProcessController(parameters, pid); + + // assert + assertThat(controller).isInstanceOf(MBeanProcessController.class); + } + + @Test + public void createProcessController_withoutAttachAPI_returnsFileProcessController() + throws Exception { + // arrange + System.setProperty(PROPERTY_DISABLE_ATTACH_API, "true"); + factory = new ProcessControllerFactory(); + + // act + ProcessController controller = factory.createProcessController(parameters, pid); + + // assert + assertThat(controller).isInstanceOf(FileProcessController.class); + } + + @Test + public void createProcessController_withNullParameters_throwsNullPointerException() + throws Exception { + // arrange + parameters = null; + + // act/assert + assertThatThrownBy(() -> factory.createProcessController(parameters, pid)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid parameters 'null' specified"); + } + + @Test + public void createProcessController_withZeroPid_throwsIllegalArgumentException() + throws Exception { + // arrange + pid = 0; + + // act/assert + assertThatThrownBy(() -> factory.createProcessController(parameters, 0)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid pid '" + 0 + "' specified"); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java new file mode 100644 index 0000000..c98f026 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessLauncherContextTest.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static java.util.Collections.synchronizedList; +import static org.apache.geode.internal.process.ProcessLauncherContext.getOverriddenDefaults; +import static org.apache.geode.internal.process.ProcessLauncherContext.getStartupListener; +import static org.apache.geode.internal.process.ProcessLauncherContext.isRedirectingOutput; +import static org.apache.geode.internal.process.ProcessLauncherContext.remove; +import static org.apache.geode.internal.process.ProcessLauncherContext.set; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.UnitTest; + +/** + * Unit tests for {@link ProcessLauncherContext}. + */ +@Category(UnitTest.class) +public class ProcessLauncherContextTest { + + private boolean redirectOutput; + private Properties overriddenDefaults; + private StartupStatusListener startupListener; + private List statusMessageList; + + @Before + public void before() throws Exception { + redirectOutput = false; + overriddenDefaults = new Properties(); + startupListener = mock(StartupStatusListener.class); + statusMessageList = synchronizedList(new ArrayList<>()); + } + + @After + public void after() throws Exception { + remove(); + } + + @Test + public void isRedirectingOutput_defaultsToFalse() throws Exception { + assertThat(isRedirectingOutput()).isFalse(); + } + + @Test + public void getOverriddenDefaults_defaultsToEmpty() throws Exception { + assertThat(getOverriddenDefaults()).isEmpty(); + } + + @Test + public void getStartupListener_defaultsToNull() throws Exception { + assertThat(getStartupListener()).isNull(); + } + + @Test + public void null_overriddenDefaults_throwsIllegalArgumentException() throws Exception { + // arrange + overriddenDefaults = null; + + // act/assert + assertThatThrownBy(() -> set(redirectOutput, overriddenDefaults, startupListener)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid overriddenDefaults 'null' specified"); + } + + @Test + public void null_startupListener_isAllowed() throws Exception { + // arrange + startupListener = null; + + // act + set(redirectOutput, overriddenDefaults, startupListener); + + // assert + assertThat(getStartupListener()).isNull(); + } + + @Test + public void empty_overriddenDefaults_isAllowed() throws Exception { + // act + set(redirectOutput, overriddenDefaults, startupListener); + + // assert + assertThat(getOverriddenDefaults()).isEmpty(); + } + + @Test + public void isRedirectingOutput_returnsPassedValue() throws Exception { + // arrange + redirectOutput = true; + + // act + set(redirectOutput, overriddenDefaults, startupListener); + + // assert + assertThat(isRedirectingOutput()).isTrue(); + } + + @Test + public void getOverriddenDefaults_returnsPassedInProps() throws Exception { + // arrange + overriddenDefaults.setProperty("key", "value"); + + // act + set(redirectOutput, overriddenDefaults, startupListener); + + // assert + assertThat(getOverriddenDefaults()).hasSize(1).containsEntry("key", "value"); + } + + @Test + public void getStartupListener_returnsPassedInListener() throws Exception { + // arrange + overriddenDefaults.setProperty("key", "value"); + + // act + set(redirectOutput, overriddenDefaults, startupListener); + + // assert + assertThat(getStartupListener()).isSameAs(startupListener); + } + + @Test + public void remove_clearsOverriddenDefaults() throws Exception { + // arrange + overriddenDefaults.setProperty("key", "value"); + set(false, overriddenDefaults, startupListener); + + // act + remove(); + + // assert + assertThat(getOverriddenDefaults()).isEmpty(); + } + + @Test + public void remove_unsetsRedirectOutput() throws Exception { + // arrange + redirectOutput = true; + set(redirectOutput, overriddenDefaults, startupListener); + + // act + remove(); + + // assert + assertThat(isRedirectingOutput()).isFalse(); + } + + @Test + public void remove_clearsStartupListener() throws Exception { + // arrange + startupListener = statusMessage -> statusMessageList.add(statusMessage); + set(redirectOutput, overriddenDefaults, startupListener); + + // act + remove(); + + // assert + assertThat(getStartupListener()).isNull(); + } + + @Test + public void startupListener_installsInStartupStatus() throws Exception { + // arrange + startupListener = statusMessage -> statusMessageList.add(statusMessage); + + // act + set(redirectOutput, overriddenDefaults, startupListener); + + // assert + assertThat(StartupStatus.getStartupListener()).isSameAs(startupListener); + } + + @Test + public void remove_uninstallsInStartupStatus() throws Exception { + // arrange + startupListener = statusMessage -> statusMessageList.add(statusMessage); + set(redirectOutput, overriddenDefaults, startupListener); + + // act + remove(); + + // assert + assertThat(StartupStatus.getStartupListener()).isNull(); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java b/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java deleted file mode 100755 index 32a7f79..0000000 --- a/geode-core/src/test/java/org/apache/geode/internal/process/ProcessStreamReaderTestCase.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more contributor license - * agreements. See the NOTICE file distributed with this work for additional information regarding - * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the License. You may obtain a - * copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - */ -package org.apache.geode.internal.process; - -import static org.junit.Assert.*; - -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.Callable; - -import org.junit.After; -import org.junit.Test; - -import org.apache.geode.internal.util.StopWatch; - -/** - * Functional tests for ProcessStreamReader. - * - */ -public abstract class ProcessStreamReaderTestCase { - - /** Sleep timeout for {@link ProcessSleeps} instead of sleeping Long.MAX_VALUE */ - protected static final int PROCESS_FAILSAFE_TIMEOUT = 10 * 60 * 1000; - - /** Additional time for launched processes to live before terminating */ - protected static final int PROCESS_TIME_TO_LIVE = 3 * 500; - - /** Timeout to wait for a forked process to start */ - protected static final int WAIT_FOR_PROCESS_TO_START_TIMEOUT = 60 * 1000; - - /** - * Timeout to wait for a running process to die -- this keeps timing out so I'm increasing it very - * large - */ - protected static final int WAIT_FOR_PROCESS_TO_DIE_TIMEOUT = 5 * 60 * 1000; - - /** Timeout to wait for a new {@link ProcessStreamReader} to be running */ - protected static final int WAIT_FOR_READER_IS_RUNNING_TIMEOUT = 20 * 1000; - - /** Timeout to join to a running ProcessStreamReader thread */ - protected static final int READER_JOIN_TIMEOUT = 20 * 1000; - - /** Brief time to sleep before repeating a conditional check */ - protected static final int INTERVAL = 20; - - protected Process process; - protected ProcessStreamReader stderr; - protected ProcessStreamReader stdout; - - @After - public void stopReadersAndDestroyProcess() throws Exception { - if (this.stderr != null) { - this.stderr.stop(); - } - if (this.stdout != null) { - this.stdout.stop(); - } - if (this.process != null) { - this.process.destroy(); // this is async and can require more than 10 seconds in Jenkins - /* - * assertEventuallyFalse("Timed out destroying process after " + - * WAIT_FOR_PROCESS_TO_DIE_TIMEOUT/(60*1000) + " minutes", new Callable() { - * - * @Override public Boolean call() throws Exception { return isAlive(process); } }, - * WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL); - */ - } - } - - @Test - public void processLivesAfterClosingStreams() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start(); - this.process.getErrorStream().close(); - this.process.getOutputStream().close(); - this.process.getInputStream().close(); - assertIsAlive(process); - this.process.destroy(); - } - - @Test - public void processTerminatesWhenDestroyed() throws Exception { - this.process = new ProcessBuilder(createCommandLine(ProcessSleeps.class)).start(); - assertIsAlive(this.process); - this.process.destroy(); - assertEventuallyFalse("Timed out destroying process", new Callable() { - @Override - public Boolean call() throws Exception { - return isAlive(process); - } - }, WAIT_FOR_PROCESS_TO_DIE_TIMEOUT, INTERVAL); - assertNotEquals(0, this.process.exitValue()); - } - - protected static void assertEventuallyTrue(final String message, final Callable callable, - final int timeout, final int interval) throws Exception { - boolean done = false; - for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done = - (callable.call())) { - Thread.sleep(interval); - } - assertTrue(message + " within timeout of " + timeout + " milliseconds", done); - } - - protected static void assertEventuallyFalse(final String message, - final Callable callable, final int timeout, final int interval) throws Exception { - boolean done = false; - for (StopWatch time = new StopWatch(true); !done && time.elapsedTimeMillis() < timeout; done = - (!callable.call())) { - Thread.sleep(interval); - } - assertTrue(message + " within timeout of " + timeout + " milliseconds", done); - } - - protected static void assertIsAlive(final Process process) { - assertTrue(isAlive(process)); - } - - protected static void assertIsNotAlive(final Process process) { - assertFalse(isAlive(process)); - } - - protected static boolean isAlive(final Process process) { - try { - process.exitValue(); - return false; - } catch (IllegalThreadStateException e) { - return true; - } - } - - protected static String getJavaPath() { - String java = "java"; - // if (SystemUtils.isWindows()) { - // java = "javaw"; - // } - return new File(new File(System.getProperty("java.home"), "bin"), java).getPath(); - } - - protected static String getClassPath() { - return System.getProperty("java.class.path"); - } - - protected static String[] createCommandLine(final Class clazz) { - return createCommandLine(clazz, null); - } - - protected static String[] createCommandLine(final Class clazz, final String[] jvmArgsOpts) { - List commandLine = new ArrayList<>(); - - commandLine.add(getJavaPath()); - commandLine.add("-server"); - commandLine.add("-classpath"); - commandLine.add(getClassPath()); - - addJvmArgumentsAndOptions(commandLine, jvmArgsOpts); - - commandLine.add("-Djava.awt.headless=true"); - commandLine.add(clazz.getName()); - - return commandLine.toArray(new String[commandLine.size()]); - } - - protected static void addJvmArgumentsAndOptions(final List commandLine, - final String[] jvmArgsOpts) { - if (jvmArgsOpts != null) { - commandLine.addAll(Arrays.asList(jvmArgsOpts)); - } - } - - protected static void assertEventuallyIsRunning(final ProcessStreamReader reader) - throws Exception { - assertEventuallyTrue("Waiting for ProcessStreamReader to be running", new Callable() { - @Override - public Boolean call() throws Exception { - return reader.isRunning(); - } - }, WAIT_FOR_READER_IS_RUNNING_TIMEOUT, INTERVAL); - } - - protected static class ProcessSleeps { - public static void main(String[] args) throws InterruptedException { - Thread.sleep(PROCESS_FAILSAFE_TIMEOUT); - } - } - - protected static class ProcessThrowsError { - protected static String[] LINES = new String[] {"ProcessThrowsError is starting\n", - "ProcessThrowsError is sleeping\n", "ProcessThrowsError is throwing\n"}; - protected static String ERROR_MSG = "ProcessThrowsError throws Error"; - - public static void main(String[] args) throws InterruptedException { - System.err.print(LINES[0]); - System.err.print(LINES[1]); - Thread.sleep(PROCESS_TIME_TO_LIVE); - System.err.print(LINES[2]); - throw new Error(ERROR_MSG); - } - } - - protected static class ProcessPrintsToStdout { - protected static String[] LINES = new String[] {"ProcessPrintsToStdout is starting\n", - "ProcessPrintsToStdout is sleeping\n", "ProcessPrintsToStdout is exiting\n"}; - - public static void main(String[] args) throws InterruptedException { - System.out.print(LINES[0]); - System.out.print(LINES[1]); - Thread.sleep(PROCESS_TIME_TO_LIVE); - System.out.print(LINES[2]); - } - } - - protected static class ProcessPrintsToStderr { - protected static String[] LINES = new String[] {"ProcessPrintsToStdout is starting\n", - "ProcessPrintsToStdout is sleeping\n", "ProcessPrintsToStdout is exiting\n"}; - - public static void main(String[] args) throws InterruptedException { - System.err.print(LINES[0]); - System.err.print(LINES[1]); - Thread.sleep(PROCESS_TIME_TO_LIVE); - System.err.print(LINES[2]); - } - } - - protected static class ProcessPrintsToBoth { - protected static String[] OUT_LINES = new String[] {"ProcessPrintsToBoth(out) is starting\n", - "ProcessPrintsToBoth(out) is sleeping\n", "ProcessPrintsToBoth(out) is exiting\n"}; - protected static String[] ERR_LINES = new String[] {"ProcessPrintsToBoth(err) is starting\n", - "ProcessPrintsToBoth(err) is sleeping\n", "ProcessPrintsToBoth(err) is exiting\n"}; - - public static void main(String[] args) throws InterruptedException { - System.out.print(OUT_LINES[0]); - System.err.print(ERR_LINES[0]); - System.out.print(OUT_LINES[1]); - System.err.print(ERR_LINES[1]); - Thread.sleep(PROCESS_TIME_TO_LIVE); - System.out.print(OUT_LINES[2]); - System.err.print(ERR_LINES[2]); - } - } -} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java b/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java new file mode 100644 index 0000000..04e23f3 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/StartupStatusTest.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process; + +import static java.util.Collections.synchronizedList; +import static org.apache.geode.internal.process.StartupStatus.clearListener; +import static org.apache.geode.internal.process.StartupStatus.getStartupListener; +import static org.apache.geode.internal.process.StartupStatus.setListener; +import static org.apache.geode.internal.process.StartupStatus.startup; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.i18n.StringId; +import org.apache.geode.test.junit.categories.UnitTest; + +@Category(UnitTest.class) +public class StartupStatusTest { + + private StartupStatusListener listener; + private List statusMessageList; + + @Before + public void before() throws Exception { + listener = mock(StartupStatusListener.class); + statusMessageList = synchronizedList(new ArrayList<>()); + } + + @After + public void after() throws Exception { + clearListener(); + } + + @Test + public void getStartupListener_returnsNullByDefault() throws Exception { + // act/assert + assertThat(getStartupListener()).isNull(); + } + + @Test + public void setListener_null_clearsStartupListener() throws Exception { + // arrange + listener = null; + + // act + setListener(listener); + + // assert + assertThat(getStartupListener()).isNull(); + } + + @Test + public void getStartupListener_returnsSetListener() throws Exception { + // arrange + setListener(listener); + + // act/assert + assertThat(getStartupListener()).isSameAs(listener); + } + + @Test + public void clearListener_doesNothingIfNull() throws Exception { + // arrange + listener = null; + setListener(listener); + assertThat(getStartupListener()).isNull(); + + // act + clearListener(); + + // assert + assertThat(getStartupListener()).isNull(); + } + + @Test + public void clearListener_unsetsListener() throws Exception { + // arrange + setListener(listener); + assertThat(getStartupListener()).isNotNull(); + + // act + clearListener(); + + // assert + assertThat(getStartupListener()).isNull(); + } + + @Test + public void startup_nullStringId_throwsIllegalArgumentException() throws Exception { + // arrange + StringId stringId = null; + Object[] params = new Object[0]; + + // act/assert + assertThatThrownBy(() -> startup(stringId, params)).isInstanceOf(IllegalArgumentException.class) + .hasMessage("Invalid msgId 'null' specified"); + } + + @Test + public void startup_emptyParams() throws Exception { + // arrange + StringId stringId = new StringId(1, "my string"); + Object[] params = new Object[0]; + + // act + startup(stringId, params); + + // assert (does not throw) + assertThat(getStartupListener()).isNull(); + } + + @Test + public void startup_doesNothingIfNoListener() throws Exception { + // arrange + StringId stringId = new StringId(1, "my string"); + Object[] params = new Object[0]; + + // act + startup(stringId, params); + + // assert (does nothing) + assertThat(getStartupListener()).isNull(); + } + + @Test + public void startup_invokesListener() throws Exception { + // arrange + listener = statusMessage -> statusMessageList.add(statusMessage); + StringId stringId = new StringId(1, "my string"); + Object[] params = new Object[0]; + setListener(listener); + + // act + startup(stringId, params); + + // assert + assertThat(statusMessageList).hasSize(1).contains("my string"); + } + + @Test + public void startupTwice_invokesListenerTwice() throws Exception { + // arrange + listener = statusMessage -> statusMessageList.add(statusMessage); + StringId stringIdOne = new StringId(1, "my string"); + StringId stringIdTwo = new StringId(2, "other string"); + Object[] params = new Object[0]; + setListener(listener); + + // act + startup(stringIdOne, params); + startup(stringIdTwo, params); + + // assert + assertThat(statusMessageList).hasSize(2).contains("my string").contains("other string"); + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java new file mode 100644 index 0000000..3acf0a6 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/EmptyFileWriter.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process.io; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; + +/** + * Creates an empty file. + */ +public class EmptyFileWriter { + + private final File file; + + public EmptyFileWriter(final File file) { + this.file = file; + } + + public File createNewFile() throws IOException { + assertThat(file).doesNotExist(); + assertThat(file.createNewFile()).isTrue(); + assertThat(file).exists(); + return file; + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java new file mode 100644 index 0000000..4f405bf --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileReader.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process.io; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +public class IntegerFileReader { + + private final File file; + + public IntegerFileReader(final File file) { + this.file = file; + } + + public int readFromFile() throws IOException { + assertThat(file).exists(); + try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { + return Integer.parseInt(bufferedReader.readLine()); + } + } +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java new file mode 100644 index 0000000..47f54bc --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/IntegerFileWriter.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process.io; + +import java.io.File; +import java.io.IOException; + +/** + * Writes an integer to the file. + */ +public class IntegerFileWriter extends StringFileWriter { + + public IntegerFileWriter(final File file) { + super(file); + } + + public void writeToFile(final int pid) throws IOException { + writeToFile(String.valueOf(pid)); + } + +} http://git-wip-us.apache.org/repos/asf/geode/blob/894f3ee7/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java ---------------------------------------------------------------------- diff --git a/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java b/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java new file mode 100644 index 0000000..76db475 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/internal/process/io/StringFileWriter.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for additional information regarding + * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License + * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.geode.internal.process.io; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +/** + * Writes a string to the file. + */ +public class StringFileWriter { + + private final File file; + + public StringFileWriter(final File file) { + this.file = file; + } + + public void writeToFile(final String string) throws IOException { + assertThat(file).doesNotExist(); + try (FileWriter writer = new FileWriter(file)) { + writer.write(string); + writer.flush(); + } + assertThat(file).exists(); + } + +}