blob: 4ae8b762e9979fcaf83e7a49609c8bb0d2f59456 [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 org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang3.JavaVersion;
import org.apache.commons.lang3.SystemUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.internal.UniquePortSupplier;
import org.apache.geode.internal.serialization.Version;
import org.apache.geode.management.internal.cli.i18n.CliStrings;
import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
import org.apache.geode.test.junit.categories.BackwardCompatibilityTest;
import org.apache.geode.test.junit.rules.gfsh.GfshRule;
import org.apache.geode.test.junit.rules.gfsh.GfshScript;
import org.apache.geode.test.junit.runners.CategoryWithParameterizedRunnerFactory;
import org.apache.geode.test.version.TestVersion;
import org.apache.geode.test.version.VersionManager;
/**
* This test iterates through the versions of Geode and executes session client compatibility with
* the current version of Geode.
*/
@Category({BackwardCompatibilityTest.class})
@RunWith(Parameterized.class)
@Parameterized.UseParametersRunnerFactory(CategoryWithParameterizedRunnerFactory.class)
public class Tomcat8ClientServerRollingUpgradeTest {
private final UniquePortSupplier portSupplier = new UniquePortSupplier();
private final String oldVersion;
private String locatorDir;
private String server1Dir;
private String server2Dir;
@Parameterized.Parameters(name = "{0}")
public static Collection<String> data() {
List<String> result = VersionManager.getInstance().getVersionsWithoutCurrent();
String minimumVersion =
SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_9) ? "1.8.0" : "1.7.0";
result.removeIf(s -> TestVersion.compare(s, minimumVersion) < 0);
return result;
}
@Rule
public transient GfshRule oldGfsh;
@Rule
public final transient GfshRule currentGfsh = new GfshRule();
@Rule
public TemporaryFolder tempFolder = new TemporaryFolder();
@Rule
public transient TestName testName = new TestName();
protected transient Client client;
protected transient ContainerManager manager;
protected TomcatInstall tomcat8AndOldModules;
protected TomcatInstall tomcat8AndCurrentModules;
protected int locatorPort;
protected int locatorJmxPort;
protected String classPathTomcat8AndCurrentModules;
private String classPathTomcat8AndOldModules;
public Tomcat8ClientServerRollingUpgradeTest(String version) {
this.oldVersion = version;
oldGfsh = new GfshRule(oldVersion);
}
protected void startServer(String name, String classPath, int locatorPort, GfshRule gfsh,
String serverDir) throws Exception {
CommandStringBuilder command = new CommandStringBuilder(CliStrings.START_SERVER);
command.addOption(CliStrings.START_SERVER__NAME, name);
command.addOption(CliStrings.START_SERVER__SERVER_PORT, "0");
command.addOption(CliStrings.START_SERVER__CLASSPATH, classPath);
command.addOption(CliStrings.START_SERVER__LOCATORS, "localhost[" + locatorPort + "]");
command.addOption(CliStrings.START_SERVER__DIR, serverDir);
gfsh.execute(GfshScript.of(command.toString()).expectExitCode(0));
}
protected void startLocator(String name, String classPath, int port, GfshRule gfsh,
String locatorDir) throws Exception {
CommandStringBuilder locStarter = new CommandStringBuilder(CliStrings.START_LOCATOR);
locStarter.addOption(CliStrings.START_LOCATOR__MEMBER_NAME, name);
locStarter.addOption(CliStrings.START_LOCATOR__CLASSPATH, classPath);
locStarter.addOption(CliStrings.START_LOCATOR__PORT, Integer.toString(port));
locStarter.addOption(CliStrings.START_LOCATOR__DIR, locatorDir);
locStarter.addOption(CliStrings.START_LOCATOR__HTTP_SERVICE_PORT, "0");
locStarter.addOption(CliStrings.START_LOCATOR__J,
"-Dgemfire.jmx-manager-port=" + locatorJmxPort);
gfsh.execute(GfshScript.of(locStarter.toString()).expectExitCode(0));
}
@Before
public void setup() throws Exception {
VersionManager versionManager = VersionManager.getInstance();
String installLocation = versionManager.getInstall(oldVersion);
File oldBuild = new File(installLocation);
File oldModules = new File(installLocation + "/tools/Modules/");
tomcat8AndOldModules =
new TomcatInstall("Tomcat8AndOldModules", TomcatInstall.TomcatVersion.TOMCAT8,
ContainerInstall.ConnectionType.CLIENT_SERVER,
oldModules.getAbsolutePath(),
oldBuild.getAbsolutePath() + "/lib",
portSupplier::getAvailablePort);
tomcat8AndCurrentModules =
new TomcatInstall("Tomcat8AndCurrentModules", TomcatInstall.TomcatVersion.TOMCAT8,
ContainerInstall.ConnectionType.CLIENT_SERVER,
portSupplier::getAvailablePort);
classPathTomcat8AndOldModules = getClassPathTomcat8AndOldModules();
classPathTomcat8AndCurrentModules = getClassPathTomcat8AndCurrentModules();
// Get available port for the locator
locatorPort = portSupplier.getAvailablePort();
locatorJmxPort = portSupplier.getAvailablePort();
tomcat8AndOldModules.setDefaultLocatorPort(locatorPort);
tomcat8AndCurrentModules.setDefaultLocatorPort(locatorPort);
client = new Client();
manager = new ContainerManager();
// Due to parameterization of the test name, the URI would be malformed. Instead, it strips off
// the [] symbols
manager.setTestName(testName.getMethodName().replace("[", "").replace("]", ""));
locatorDir = tempFolder.newFolder("loc").getPath();
server1Dir = tempFolder.newFolder("server1").getPath();
server2Dir = tempFolder.newFolder("server2").getPath();
}
/**
* Stops all containers that were previously started and cleans up their configurations
*/
@After
public void stop() throws Exception {
manager.stopAllActiveContainers();
manager.cleanUp();
CommandStringBuilder connect = new CommandStringBuilder(CliStrings.CONNECT)
.addOption(CliStrings.CONNECT__LOCATOR, "localhost[" + locatorPort + "]");
CommandStringBuilder command = new CommandStringBuilder(CliStrings.SHUTDOWN);
command.addOption(CliStrings.INCLUDE_LOCATORS, "true");
final GfshScript script = GfshScript.of(connect.toString(), command.toString());
try {
oldGfsh.execute(script);
} catch (Throwable e) {
// ignore
}
try {
currentGfsh.execute(script);
} catch (Throwable e) {
// ignore
}
}
@Test
public void canDoARollingUpgradeOfGeodeServersWithSessionModules() throws Exception {
startLocator("loc", classPathTomcat8AndOldModules, locatorPort, oldGfsh, locatorDir);
startServer("server1", classPathTomcat8AndOldModules, locatorPort, oldGfsh, server1Dir);
startServer("server2", classPathTomcat8AndOldModules, locatorPort, oldGfsh, server2Dir);
createRegion(oldGfsh);
// Start two tomcat servers with the old geode modules
ServerContainer container1 = manager.addContainer(tomcat8AndOldModules);
ServerContainer container2 = manager.addContainer(tomcat8AndOldModules);
// This has to happen at the start of every test
manager.startAllInactiveContainers();
verifySessionReplication();
// Upgrade the geode locator
stopLocator(oldGfsh, locatorDir);
startLocator("loc", classPathTomcat8AndCurrentModules, locatorPort, currentGfsh, locatorDir);
// Upgrade a server
stopServer(oldGfsh, server1Dir);
startServer("server1", classPathTomcat8AndCurrentModules, locatorPort, currentGfsh, server1Dir);
// verify again
verifySessionReplication();
// Upgrade second server
stopServer(oldGfsh, server2Dir);
startServer("server2", classPathTomcat8AndCurrentModules, locatorPort, currentGfsh, server2Dir);
// verify again
verifySessionReplication();
// Upgrade a tomcat server
container1.stop();
manager.removeContainer(container1);
ServerContainer newContainer1 = manager.addContainer(tomcat8AndCurrentModules);
newContainer1.start();
verifySessionReplication();
// Upgrade the second tomcat server
container2.stop();
manager.removeContainer(container2);
ServerContainer newContainer2 = manager.addContainer(tomcat8AndCurrentModules);
newContainer2.start();
verifySessionReplication();
}
private void createRegion(GfshRule gfsh) {
CommandStringBuilder connect = new CommandStringBuilder(CliStrings.CONNECT)
.addOption(CliStrings.CONNECT__LOCATOR, "localhost[" + locatorPort + "]");
CommandStringBuilder command = new CommandStringBuilder(CliStrings.CREATE_REGION);
command.addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
RegionShortcut.PARTITION_REDUNDANT.name())
.addOption(CliStrings.CREATE_REGION__REGION, "gemfire_modules_sessions")
.addOption(CliStrings.CREATE_REGION__STATISTICSENABLED, "true")
.addOption(CliStrings.ENTRY_IDLE_TIME_CUSTOM_EXPIRY,
"org.apache.geode.modules.util.SessionCustomExpiry");
final GfshScript script = GfshScript.of(connect.toString(), command.toString());
gfsh.execute(script);
}
private void stopLocator(GfshRule gfsh, String locatorDir) {
CommandStringBuilder command = new CommandStringBuilder(CliStrings.STOP_LOCATOR)
.addOption(CliStrings.STOP_LOCATOR__DIR, locatorDir);
gfsh.execute(command.toString());
}
private void stopServer(GfshRule gfsh, String serverDir) {
CommandStringBuilder command = new CommandStringBuilder(CliStrings.STOP_SERVER)
.addOption(CliStrings.STOP_SERVER__DIR, serverDir);
gfsh.execute(command.toString());
}
private void verifySessionReplication() throws IOException, URISyntaxException {
String key = "value_testSessionPersists";
String value = "Foo" + System.currentTimeMillis();
client.setPort(Integer.parseInt(manager.getContainerPort(0)));
Client.Response resp = client.set(key, value);
String cookie = resp.getSessionCookie();
for (int i = 0; i < manager.numContainers(); i++) {
System.out.println("Checking get for container:" + i);
client.setPort(Integer.parseInt(manager.getContainerPort(i)));
resp = client.get(key);
assertEquals("Sessions are not replicating properly", cookie, resp.getSessionCookie());
assertEquals("Session data is not replicating properly", value, resp.getResponse());
}
}
/**
* If this test breaks due to a change in required jars, please update the
* "Setting up the Module" section of the Tomcat module documentation!
*
* Returns the jars required on the classpath for the old modules. This list may
* differ from the list required by the current modules at some point in the future, hence the
* duplication of the requiredClasspathJars array.
*
* @return Paths to required jars
*/
private String getClassPathTomcat8AndOldModules() {
final String[] requiredClasspathJars = {
"/lib/geode-modules-" + oldVersion + ".jar",
"/lib/geode-modules-tomcat8-" + oldVersion + ".jar",
"/lib/servlet-api.jar",
"/lib/catalina.jar",
"/lib/tomcat-util.jar",
"/bin/tomcat-juli.jar"
};
return getRequiredClasspathJars(tomcat8AndOldModules.getHome(), requiredClasspathJars);
}
/**
* If this test breaks due to a change in required jars, please update the
* "Setting up the Module" section of the Tomcat module documentation!
*
* Returns the jars required on the classpath for the current modules. This list may
* differ from the list required by the old modules at some point in the future, hence the
* duplication of the requiredClasspathJars array.
*
* @return Paths to required jars
*/
private String getClassPathTomcat8AndCurrentModules() {
String currentVersion = Version.CURRENT.getName();
final String[] requiredClasspathJars = {
"/lib/geode-modules-" + currentVersion + ".jar",
"/lib/geode-modules-tomcat8-" + currentVersion + ".jar",
"/lib/servlet-api.jar",
"/lib/catalina.jar",
"/lib/tomcat-util.jar",
"/bin/tomcat-juli.jar"
};
return getRequiredClasspathJars(tomcat8AndCurrentModules.getHome(), requiredClasspathJars);
}
private String getRequiredClasspathJars(final String tomcat8AndRequiredModules,
final String[] requiredClasspathJars) {
StringBuilder completeJarList = new StringBuilder();
for (String requiredJar : requiredClasspathJars) {
completeJarList.append(tomcat8AndRequiredModules)
.append(requiredJar)
.append(File.pathSeparator);
}
completeJarList.deleteCharAt(completeJarList.length() - 1);
return completeJarList.toString();
}
}