/*
 * 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.GemFireVersion;
import org.apache.geode.internal.UniquePortSupplier;
import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
import org.apache.geode.management.internal.i18n.CliStrings;
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, TomcatInstall.CommitValve.DEFAULT);

    tomcat8AndCurrentModules =
        new TomcatInstall("Tomcat8AndCurrentModules", TomcatInstall.TomcatVersion.TOMCAT8,
            ContainerInstall.ConnectionType.CLIENT_SERVER,
            portSupplier::getAvailablePort, TomcatInstall.CommitValve.DEFAULT);

    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 = GemFireVersion.getGemFireVersion();

    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();
  }
}
