blob: ba191c68b541b09014fdf47ebcd39c1839ccac59 [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.session.tests;
import static java.lang.System.lineSeparator;
import static java.nio.charset.Charset.defaultCharset;
import static org.apache.commons.io.FileUtils.readLines;
import static org.apache.geode.session.tests.ContainerInstall.GEODE_BUILD_HOME;
import static org.apache.geode.session.tests.ContainerInstall.TMP_DIR;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.IntSupplier;
import org.junit.Assume;
/**
* Container for a generic app server
*
* Extends {@link ServerContainer} to form a basic container which sets up a GenericAppServer
* container. Currently being used solely for Jetty 9 containers.
*
* The container modifies a copy of the session testing war using the modify_war_file script in
* order to properly implement geode session replication for generic application servers. That means
* that tests using this container will only run on linux.
*
* In theory, adding support for additional containers should just be a matter of changing the
* {@link GenericAppServerInstall} to support other installations, since this container does not
* depend upon the type of appserver in any way.
*/
public class GenericAppServerContainer extends ServerContainer {
private final File modifyWarScript;
private final File modifyWarScriptLog;
private static final String DEFAULT_GENERIC_APPSERVER_WAR_DIR = TMP_DIR + "/cargo_wars/";
/**
* Setup the generic appserver container
*
* Sets up a configuration for the container using the specified installation and configuration
* home. Finds the script needed to modify the war file, sets up the new WAR file to modify by
* creating a temporary WAR file to use, deploys the war to the Cargo container, and sets various
* container properties (i.e. locator, local cache, etc.)
*/
public GenericAppServerContainer(GenericAppServerInstall install, File containerConfigHome,
String containerDescriptors, IntSupplier portSupplier) throws IOException {
super(install, containerConfigHome, containerDescriptors, portSupplier);
// Setup modify war script file so that it is executable and easily findable
modifyWarScript = new File(install.getModulePath() + "/bin/modify_war");
modifyWarScript.setExecutable(true);
// Setup modify_war script logging file
modifyWarScriptLog = new File(cargoLogDir + "/warScript.log");
modifyWarScriptLog.createNewFile();
// Ignore tests that are running on windows, since they can't run the modify war script
Assume.assumeFalse(System.getProperty("os.name").toLowerCase().contains("win"));
// Create temp war file to use
File warDir = new File(DEFAULT_GENERIC_APPSERVER_WAR_DIR);
warDir.mkdirs();
setWarFile(File.createTempFile(description, ".war", warDir));
// Deploy war file to container configuration
deployWar();
// Setup the default installations locators
setLocator(install.getDefaultLocatorAddress(), install.getDefaultLocatorPort());
// Make sure that local caches are disabled by default
setCacheProperty("enable_local_cache",
Boolean.toString(install.getConnectionType().enableLocalCache()));
}
/**
* Builds the command needed to run the {@link #modifyWarScript}
*
* The command is built as an array list of strings with each element representing a string
* separated by a space on the command line. For example, the list {'-t', 'geode'} would represent
* 'modify_war -t geode' on the command line.
*
* The command built points towards the {@link ContainerInstall#getWarFilePath()} as the starting
* file and the {@link #warFile} as the output file. Cache and system properties are specified
* when modifying the WAR, so the elements contained within the {@link #cacheProperties} and
* {@link #systemProperties} maps are also added to the command built.
*/
private List<String> buildCommand() throws IOException {
ContainerInstall install = getInstall();
// Start command list
List<String> command = new ArrayList<>();
// Path to the modify war script to run
command.add(modifyWarScript.getAbsolutePath());
// Path to the WAR file to modify
command.add("-w");
command.add(install.getWarFilePath());
// Get connection type for the WAR (peer-to-peer or client-server)
command.add("-t");
command.add(install.getConnectionType().getName());
// Path to the modified version of the origin WAR file
command.add("-o");
command.add(getWarFile().getAbsolutePath());
// Add all the cache properties setup to the WAR file
for (String property : cacheProperties.keySet()) {
command.add("-p");
command.add("gemfire.cache." + property + "=" + getCacheProperty(property));
}
// Add all the system properties to the WAR file
for (String property : systemProperties.keySet()) {
command.add("-p");
command.add("gemfire.property." + property + "=" + getSystemProperty(property));
}
return command;
}
/**
* Modifies the {@link ContainerInstall#getWarFilePath()} for container use, by simulating a
* command line execution of the modify_war_file script using the commands built from
* {@link #buildCommand()}
*
* The modified WAR file is sent to {@link #warFile}.
*
* @throws IOException If the command executed returns with a non-zero exit code.
*/
private void modifyWarFile() throws IOException, InterruptedException {
// Build the environment to run the command
ProcessBuilder builder = new ProcessBuilder();
builder.environment().put("GEODE", GEODE_BUILD_HOME);
builder.inheritIO();
// Setup the environment builder with the command
builder.command(buildCommand());
// Redirect the command line logging to a file
builder.redirectError(modifyWarScriptLog);
builder.redirectOutput(modifyWarScriptLog);
logger.info("Running command: " + String.join(" ", builder.command()));
// Run the command
Process process = builder.start();
// Wait for the command to finish
int exitCode = process.waitFor();
// Throw error if bad exit
if (exitCode != 0) {
StringBuilder sb = new StringBuilder();
sb.append("Unable to run modify_war script, command: ").append(builder.command());
sb.append(lineSeparator());
sb.append("check log file: ");
for (String line : readLines(modifyWarScriptLog, defaultCharset())) {
sb.append(lineSeparator());
sb.append(line);
}
throw new IOException(sb.toString());
}
}
/**
* Update the container's settings by calling {@link #modifyWarFile()} method
*/
@Override
public void writeSettings() throws Exception {
modifyWarFile();
}
}