blob: 4c582c334062ba69dbfe00546e32aabaf2273fcc [file] [log] [blame]
/*
* 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.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.geode.internal.DistributionLocator.TEST_OVERRIDE_DEFAULT_PORT_PROPERTY;
import static org.apache.geode.internal.process.ProcessUtils.isProcessAlive;
import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.BindException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.After;
import org.junit.Before;
import org.apache.geode.distributed.AbstractLauncher.Status;
import org.apache.geode.distributed.LocatorLauncher.Builder;
import org.apache.geode.distributed.LocatorLauncher.Command;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.internal.process.ProcessStreamReader;
import org.apache.geode.internal.process.ProcessStreamReader.InputListener;
/**
* Abstract base class for integration tests of {@link LocatorLauncher} as an application main in a
* forked JVM.
*
* @since GemFire 8.0
*/
public abstract class LocatorLauncherRemoteIntegrationTestCase
extends LocatorLauncherIntegrationTestCase implements UsesLocatorCommand {
private final AtomicBoolean threwBindException = new AtomicBoolean();
private volatile Process process;
private volatile ProcessStreamReader processOutReader;
private volatile ProcessStreamReader processErrReader;
private LocatorCommand locatorCommand;
@Before
public void setUp() throws Exception {
locatorCommand = new LocatorCommand(this);
}
@After
public void tearDownAbstractLocatorLauncherRemoteIntegrationTestCase() {
if (process != null) {
process.destroy();
}
if (processOutReader != null && processOutReader.isRunning()) {
processOutReader.stop();
}
if (processErrReader != null && processErrReader.isRunning()) {
processErrReader.stop();
}
}
@Override
public List<String> getJvmArguments() {
List<String> jvmArguments = new ArrayList<>();
jvmArguments.add("-D" + DistributionConfig.GEMFIRE_PREFIX + "log-level=config");
jvmArguments.add("-D" + TEST_OVERRIDE_DEFAULT_PORT_PROPERTY + "=" + defaultLocatorPort);
return jvmArguments;
}
@Override
public String getName() {
return getUniqueName();
}
protected void assertStopOf(final Process process) {
await()
.atMost(AWAIT_MILLIS, MILLISECONDS)
.untilAsserted(() -> assertThat(process.isAlive()).isFalse());
}
/**
* Please leave unused parameter throwableClass for improved readability.
*/
protected void assertThatLocatorThrew(Class<? extends Throwable> throwableClass) {
assertThat(threwBindException.get()).isTrue();
}
protected void assertThatPidIsAlive(final int pid) {
assertThat(pid).isGreaterThan(0);
assertThat(isProcessAlive(pid)).isTrue();
}
protected void assertThatProcessIsNotAlive(final Process process) {
assertThat(process.isAlive()).isFalse();
}
@Override
protected LocatorLauncher givenRunningLocator() {
return givenRunningLocator(new LocatorCommand(this).withCommand(Command.START));
}
protected LocatorLauncher givenRunningLocator(final LocatorCommand command) {
return awaitStart(command);
}
protected LocatorCommand addJvmArgument(final String arg) {
return locatorCommand.addJvmArgument(arg);
}
protected LocatorCommand withForce() {
return withForce(true);
}
protected LocatorCommand withForce(final boolean value) {
return locatorCommand.force(value);
}
protected LocatorCommand withPort(final int port) {
return locatorCommand.withPort(port);
}
protected Process getLocatorProcess() {
return process;
}
@Override
protected LocatorLauncher startLocator() {
return awaitStart(locatorCommand);
}
protected LocatorLauncher startLocator(final LocatorCommand command) {
return awaitStart(command);
}
protected LocatorLauncher startLocator(final LocatorCommand command,
final InputListener outListener, final InputListener errListener) {
executeCommandWithReaders(command.create(), outListener, errListener);
LocatorLauncher launcher = awaitStart(getWorkingDirectory());
assertThat(process.isAlive()).isTrue();
return launcher;
}
protected void startLocatorShouldFail(final LocatorCommand command) throws InterruptedException {
awaitStartFail(command, createBindExceptionListener("sysout", threwBindException),
createBindExceptionListener("syserr", threwBindException));
}
protected void startLocatorShouldFail() throws InterruptedException {
startLocatorShouldFail(locatorCommand);
}
private void assertThatProcessIsNotAlive() {
assertThatProcessIsNotAlive(process);
}
private void awaitStartFail(final LocatorCommand command, final InputListener outListener,
final InputListener errListener) throws InterruptedException {
executeCommandWithReaders(command.create(), outListener, errListener);
process.waitFor(AWAIT_MILLIS, MILLISECONDS);
assertThatProcessIsNotAlive();
assertThat(process.exitValue()).isEqualTo(1);
}
private LocatorLauncher awaitStart(final File workingDirectory) {
try {
launcher = new Builder().setWorkingDirectory(workingDirectory.getCanonicalPath()).build();
awaitStart(launcher);
assertThat(process.isAlive()).isTrue();
return launcher;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private LocatorLauncher awaitStart(final LocatorCommand command) {
executeCommandWithReaders(command);
LocatorLauncher launcher = awaitStart(getWorkingDirectory());
assertThat(process.isAlive()).isTrue();
return launcher;
}
@Override
protected LocatorLauncher awaitStart(final LocatorLauncher launcher) {
await()
.atMost(AWAIT_MILLIS, MILLISECONDS)
.untilAsserted(() -> {
try {
assertThat(launcher.status().getStatus()).isEqualTo(Status.ONLINE);
} catch (Error | Exception e) {
throw new AssertionError(statusFailedWithException(e), e);
}
});
assertThat(process.isAlive()).isTrue();
return launcher;
}
protected String statusFailedWithException(Throwable cause) {
StringBuilder sb = new StringBuilder();
sb.append("Status failed with exception: ");
sb.append("process.isAlive()=").append(process.isAlive());
sb.append(", processErrReader").append(processErrReader);
sb.append(", processOutReader").append(processOutReader);
sb.append(", message").append(cause.getMessage());
return sb.toString();
}
private InputListener createBindExceptionListener(final String name,
final AtomicBoolean threwBindException) {
return createExpectedListener(name, BindException.class.getName(), threwBindException);
}
private void executeCommandWithReaders(final List<String> command) {
try {
process = new ProcessBuilder(command).directory(getWorkingDirectory()).start();
processOutReader = new ProcessStreamReader.Builder(process)
.inputStream(process.getInputStream())
.build()
.start();
processErrReader = new ProcessStreamReader.Builder(process)
.inputStream(process.getErrorStream())
.build()
.start();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void executeCommandWithReaders(final List<String> command,
final InputListener outListener, final InputListener errListener) {
try {
process = new ProcessBuilder(command).directory(getWorkingDirectory()).start();
processOutReader = new ProcessStreamReader.Builder(process)
.inputStream(process.getInputStream())
.inputListener(outListener)
.build()
.start();
processErrReader = new ProcessStreamReader.Builder(process)
.inputStream(process.getErrorStream())
.inputListener(errListener)
.build()
.start();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private void executeCommandWithReaders(final LocatorCommand command) {
executeCommandWithReaders(command.create());
}
}