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