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