This is an automated email from the ASF dual-hosted git repository.

eshu11 pushed a commit to branch feature/GEODE-7109
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/feature/GEODE-7109 by this 
push:
     new 04bc76c  GEODE-7109: add test case that multiple sessions can be 
maintained.
04bc76c is described below

commit 04bc76cb152aa80f5e06cc820dec9285b1559a29
Author: Eric Shu <eshu@EricMacBookPro.local>
AuthorDate: Fri Feb 14 12:39:18 2020 -0800

    GEODE-7109: add test case that multiple sessions can be maintained.
    
      * work around an known issue by verifying after HARegionQueue is drained.
---
 .../apache/geode/modules/session/QueryCommand.java |   3 +-
 extensions/session-testing-war/build.gradle        |   5 +
 .../geode/modules/session/CommandServlet.java      |  54 +++++
 .../geode/modules/session/GetQueueSize.java}       |  43 ++--
 .../apache/geode/modules/session/QueryCommand.java |   4 +-
 .../org/apache/geode/session/tests/Client.java     |  12 +
 .../apache/geode/session/tests/CargoTestBase.java  |  58 +++--
 .../apache/geode/session/tests/Tomcat6Test.java    |   2 +-
 .../apache/geode/session/tests/Tomcat7Test.java    |   2 +-
 .../apache/geode/session/tests/Tomcat8Test.java    |   2 +-
 .../apache/geode/session/tests/Tomcat9Test.java    |   2 +-
 .../session/tests/TomcatClientServerTest.java      |  52 +++-
 .../org/apache/geode/session/tests/TomcatTest.java | 267 +++++++++++++++++++++
 13 files changed, 456 insertions(+), 50 deletions(-)

diff --git 
a/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/QueryCommand.java
 
b/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/QueryCommand.java
index 62d5ee9..a6d9594 100644
--- 
a/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/QueryCommand.java
+++ 
b/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/QueryCommand.java
@@ -33,6 +33,7 @@ public enum QueryCommand {
 
   UNKNOWN,
 
-  FUNCTION;
+  FUNCTION,
 
+  WAIT_UNTIL_QUEUE_DRAINED;
 }
diff --git a/extensions/session-testing-war/build.gradle 
b/extensions/session-testing-war/build.gradle
index 1e3e366..05f8a9a 100644
--- a/extensions/session-testing-war/build.gradle
+++ b/extensions/session-testing-war/build.gradle
@@ -24,6 +24,11 @@ apply plugin: 'war'
 dependencies {
   compile(platform(project(':boms:geode-all-bom')))
   compile('javax.servlet:javax.servlet-api')
+    compileOnly(project(':extensions:geode-modules'))
+    compileOnly(project(':geode-assembly:geode-assembly-test'))
+    compile(project(':geode-junit')) {
+        exclude module: 'geode-core'
+    }
 }
 
 war {
diff --git 
a/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/CommandServlet.java
 
b/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/CommandServlet.java
index 5a42a1d..58e8e55 100644
--- 
a/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/CommandServlet.java
+++ 
b/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/CommandServlet.java
@@ -15,8 +15,13 @@
 
 package org.apache.geode.modules.session;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
 import java.util.function.Function;
 
 import javax.servlet.ServletConfig;
@@ -26,6 +31,18 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import org.apache.catalina.Manager;
+import org.apache.catalina.session.StandardSession;
+import org.apache.catalina.session.StandardSessionFacade;
+import org.awaitility.Duration;
+
+import org.apache.geode.cache.GemFireCache;
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.FunctionService;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.modules.session.catalina.DeltaSessionManager;
+import org.apache.geode.test.awaitility.GeodeAwaitility;
+
 public class CommandServlet extends HttpServlet {
   @SuppressWarnings("unused")
   private ServletContext context;
@@ -92,10 +109,47 @@ public class CommandServlet extends HttpServlet {
             out.write(result);
           }
           break;
+        case WAIT_UNTIL_QUEUE_DRAINED:
+          session = request.getSession();
+          DeltaSessionManager manager = (DeltaSessionManager) 
getSessionManager(session);
+          
GeodeAwaitility.await().pollInterval(Duration.TWO_HUNDRED_MILLISECONDS)
+              .untilAsserted(() -> 
assertThat(checkQueueDrained(manager)).isTrue());
+          break;
       }
     } catch (Exception e) {
       out.write("Error in servlet: " + e.toString());
       e.printStackTrace(out);
     }
   }
+
+  private boolean checkQueueDrained(DeltaSessionManager manager) {
+    GemFireCache cache = manager.getSessionCache().getCache();
+    Execution execution = FunctionService.onServers(cache);
+
+    ResultCollector collector = execution.execute(GetQueueSize.ID);
+    List list = (List) collector.getResult();
+    for (Object object : list) {
+      for (Object queue : ((Map) object).keySet()) {
+        manager.getLogger().info("client cache has queue: " + queue);
+      }
+    }
+    for (Object object : list) {
+      for (Object size : ((Map) object).values()) {
+        if ((Integer) size != 0) {
+          manager.getLogger().info("checkQueueDrained not drained with size " 
+ size);
+          return false;
+        }
+      }
+    }
+    manager.getLogger().info("checkQueueDrained drained");
+    return true;
+  }
+
+  private Manager getSessionManager(HttpSession session) throws Exception {
+    Field facadeSessionField = 
StandardSessionFacade.class.getDeclaredField("session");
+    facadeSessionField.setAccessible(true);
+    StandardSession stdSession = (StandardSession) 
facadeSessionField.get(session);
+
+    return stdSession.getManager();
+  }
 }
diff --git 
a/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/QueryCommand.java
 
b/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/GetQueueSize.java
similarity index 53%
copy from 
extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/QueryCommand.java
copy to 
extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/GetQueueSize.java
index 62d5ee9..15fd8f5 100644
--- 
a/extensions/geode-modules-test/src/main/java/org/apache/geode/modules/session/QueryCommand.java
+++ 
b/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/GetQueueSize.java
@@ -14,25 +14,26 @@
  */
 package org.apache.geode.modules.session;
 
-/**
- * Basic commands to pass to our test servlet
- */
-public enum QueryCommand {
-
-  SET,
-
-  SET_MAX_INACTIVE,
-
-  GET,
-
-  REMOVE,
-
-  INVALIDATE,
-
-  CALLBACK,
-
-  UNKNOWN,
-
-  FUNCTION;
-
+import java.util.Map;
+
+import org.apache.geode.cache.execute.Function;
+import org.apache.geode.cache.execute.FunctionContext;
+import org.apache.geode.internal.cache.InternalCache;
+import org.apache.geode.internal.cache.tier.InternalClientMembership;
+
+public class GetQueueSize implements Function {
+  public static final String ID = "get-queue-size";
+
+  @Override
+  @SuppressWarnings("unchecked")
+  public void execute(FunctionContext context) {
+    InternalCache cache = (InternalCache) context.getCache();
+    Map clientProxyMembershipIDMap = 
InternalClientMembership.getClientQueueSizes(cache);
+    context.getResultSender().lastResult(clientProxyMembershipIDMap);
+  }
+
+  @Override
+  public String getId() {
+    return ID;
+  }
 }
diff --git 
a/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/QueryCommand.java
 
b/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/QueryCommand.java
index b22787c..c1a729b 100644
--- 
a/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/QueryCommand.java
+++ 
b/extensions/session-testing-war/src/main/java/org/apache/geode/modules/session/QueryCommand.java
@@ -31,6 +31,8 @@ public enum QueryCommand {
 
   UNKNOWN,
 
-  FUNCTION;
+  FUNCTION,
+
+  WAIT_UNTIL_QUEUE_DRAINED;
 
 }
diff --git 
a/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/session/tests/Client.java
 
b/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/session/tests/Client.java
index d9257e8..c992482 100644
--- 
a/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/session/tests/Client.java
+++ 
b/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/session/tests/Client.java
@@ -248,6 +248,10 @@ public class Client {
     }
   }
 
+  public String getCookie() {
+    return cookie;
+  }
+
   private String getCookieHeader(CloseableHttpResponse resp) {
     Header lastHeader = resp.getLastHeader("Set-Cookie");
 
@@ -302,4 +306,12 @@ public class Client {
           + '\'' + '}';
     }
   }
+
+  public Response waitForQueueToDrain() throws IOException, URISyntaxException 
{
+    resetURI();
+    reqURIBuild.setParameter("cmd", 
QueryCommand.WAIT_UNTIL_QUEUE_DRAINED.name());
+    reqURIBuild.setParameter("param", null);
+
+    return doRequest(new HttpGet(reqURIBuild.build()), true);
+  }
 }
diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/CargoTestBase.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/CargoTestBase.java
index 6299a8f..3607260 100644
--- 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/CargoTestBase.java
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/CargoTestBase.java
@@ -14,6 +14,7 @@
  */
 package org.apache.geode.session.tests;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
@@ -58,6 +59,8 @@ public abstract class CargoTestBase {
   protected ContainerManager manager;
   protected ContainerInstall install;
   protected MemberVM locatorVM;
+  protected boolean dumpLogs = true;
+  protected int numberOfContainers = 2;
 
   /**
    * Should only be called once per test.
@@ -88,7 +91,7 @@ public abstract class CargoTestBase {
     install = getInstall(portSupplier::getAvailablePort);
     install.setDefaultLocatorPort(locatorVM.getPort());
 
-    manager.addContainers(2, install);
+    manager.addContainers(numberOfContainers, install);
 
     customizeContainers();
   }
@@ -104,7 +107,9 @@ public abstract class CargoTestBase {
       manager.stopAllActiveContainers();
     } finally {
       try {
-        manager.dumpLogs();
+        if (dumpLogs) {
+          manager.dumpLogs();
+        }
       } finally {
         try {
           manager.cleanUp();
@@ -121,6 +126,12 @@ public abstract class CargoTestBase {
    */
   public void getKeyValueDataOnAllClients(String key, String expectedValue, 
String expectedCookie)
       throws IOException, URISyntaxException {
+    getKeyValueDataOnAllClients(client, key, expectedValue, expectedCookie);
+  }
+
+  public void getKeyValueDataOnAllClients(Client client, String key, String 
expectedValue,
+      String expectedCookie)
+      throws IOException, URISyntaxException {
     for (int i = 0; i < manager.numContainers(); i++) {
       // Set the port for this server
       client.setPort(Integer.parseInt(manager.getContainerPort(i)));
@@ -139,22 +150,38 @@ public abstract class CargoTestBase {
         String value = resp.getResponse();
         if (!expectedValue.equals(value)) {
           LogService.getLogger().info("verifying container {} for expected 
value of {}"
-              + " for key {}, but gets response value of {}. Waiting for 
update from server.", i,
-              expectedValue, key, value);
+              + " for key {}, but gets response value of {} from client {}. 
Waiting for update from server.",
+              i, expectedValue, key, value, client);
         }
-        GeodeAwaitility.await().until(() -> 
expectedValue.equals(getResponseValue(client, key)));
+        GeodeAwaitility.await().pollInSameThread().untilAsserted(
+            () -> assertThat(getResponseValue(client, 
key)).isEqualTo(expectedValue));
       } else {
         // either p2p cache or client cache which has proxy/empty region - 
retrieving session from
         // servers
-        assertEquals("Session data is not replicating properly", 
expectedValue, resp.getResponse());
+        assertEquals("Session data is not replicating properly for key " + 
key, expectedValue,
+            resp.getResponse());
       }
     }
   }
 
+  protected void getKeyValueDataOnOperatingClient(Client client, String key, 
String expectedValue,
+      String expectedCookie, int operatingContainer)
+      throws IOException, URISyntaxException {
+    
client.setPort(Integer.parseInt(manager.getContainerPort(operatingContainer)));
+    Client.Response resp = client.get(key);
+    if (expectedCookie != null)
+      assertEquals("Sessions are not replicating properly", expectedCookie,
+          resp.getSessionCookie());
+
+    assertEquals("Session data is not replicating properly for key " + key, 
expectedValue,
+        resp.getResponse());
+
+  }
+
   private String getResponseValue(Client client, String key)
       throws IOException, URISyntaxException {
-    String value = client.get(key).getResponse();
-    LogService.getLogger().info("client gets response value of {}", value);
+    Client.Response response = client.get(key);
+    String value = response.getResponse();
     return value;
   }
 
@@ -190,8 +217,8 @@ public abstract class CargoTestBase {
   }
 
   /**
-   * Test that when a container fails, session attributes that were previously 
set in that container
-   * are still available in other containers
+   * Test that when a container fails, session attributes that were previously 
set in that
+   * container are still available in other containers
    */
   @Test
   public void failureShouldStillAllowOtherContainersDataAccess()
@@ -293,8 +320,8 @@ public abstract class CargoTestBase {
 
 
   /**
-   * Test that if one container is accessing a session, that will prevent the 
session from expiring
-   * in all containers.
+   * Test that if one container is accessing a session, that will prevent the 
session from
+   * expiring in all containers.
    */
   @Test
   public void containersShouldShareSessionExpirationReset()
@@ -329,7 +356,8 @@ public abstract class CargoTestBase {
   }
 
   /**
-   * Test that if a session attribute is removed in one container, it is 
removed from all containers
+   * Test that if a session attribute is removed in one container, it is 
removed from all
+   * containers
    */
   @Test
   public void containersShouldShareDataRemovals() throws IOException, 
URISyntaxException {
@@ -350,8 +378,8 @@ public abstract class CargoTestBase {
   }
 
   /**
-   * Test that a container added to the system after puts still can access the 
correct sessions and
-   * data.
+   * Test that a container added to the system after puts still can access the 
correct sessions
+   * and data.
    */
   @Test
   public void newContainersShouldShareDataAccess() throws Exception {
diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat6Test.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat6Test.java
index 60dface..42511c8 100644
--- 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat6Test.java
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat6Test.java
@@ -19,7 +19,7 @@ import static 
org.apache.geode.session.tests.TomcatInstall.TomcatVersion.TOMCAT6
 
 import java.util.function.IntSupplier;
 
-public class Tomcat6Test extends CargoTestBase {
+public class Tomcat6Test extends TomcatTest {
   @Override
   public ContainerInstall getInstall(IntSupplier portSupplier) throws 
Exception {
     return new TomcatInstall(getClass().getSimpleName(), TOMCAT6, 
PEER_TO_PEER, portSupplier);
diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat7Test.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat7Test.java
index 1922fdb..4b6836d 100644
--- 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat7Test.java
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat7Test.java
@@ -19,7 +19,7 @@ import static 
org.apache.geode.session.tests.TomcatInstall.TomcatVersion.TOMCAT7
 
 import java.util.function.IntSupplier;
 
-public class Tomcat7Test extends CargoTestBase {
+public class Tomcat7Test extends TomcatTest {
   @Override
   public ContainerInstall getInstall(IntSupplier portSupplier) throws 
Exception {
     return new TomcatInstall(getClass().getSimpleName(), TOMCAT7, 
PEER_TO_PEER, portSupplier);
diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat8Test.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat8Test.java
index 93a7441..97b73d9 100644
--- 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat8Test.java
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat8Test.java
@@ -19,7 +19,7 @@ import static 
org.apache.geode.session.tests.TomcatInstall.TomcatVersion.TOMCAT8
 
 import java.util.function.IntSupplier;
 
-public class Tomcat8Test extends CargoTestBase {
+public class Tomcat8Test extends TomcatTest {
   @Override
   public ContainerInstall getInstall(IntSupplier portSupplier) throws 
Exception {
     return new TomcatInstall(getClass().getSimpleName(), TOMCAT8, 
PEER_TO_PEER, portSupplier);
diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat9Test.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat9Test.java
index b7777d1..90f5392 100644
--- 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat9Test.java
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/Tomcat9Test.java
@@ -19,7 +19,7 @@ import static 
org.apache.geode.session.tests.TomcatInstall.TomcatVersion.TOMCAT9
 
 import java.util.function.IntSupplier;
 
-public class Tomcat9Test extends CargoTestBase {
+public class Tomcat9Test extends TomcatTest {
   @Override
   public ContainerInstall getInstall(IntSupplier portSupplier) throws 
Exception {
     return new TomcatInstall(getClass().getSimpleName(), TOMCAT9, 
PEER_TO_PEER, portSupplier);
diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/TomcatClientServerTest.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/TomcatClientServerTest.java
index 75af639..e86ee0d 100644
--- 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/TomcatClientServerTest.java
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/TomcatClientServerTest.java
@@ -14,26 +14,30 @@
  */
 package org.apache.geode.session.tests;
 
+
 import java.io.File;
+import java.util.ArrayList;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.rules.TemporaryFolder;
 
+import org.apache.geode.internal.serialization.Version;
 import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
 import org.apache.geode.management.internal.i18n.CliStrings;
 import org.apache.geode.test.dunit.rules.ClusterStartupRule;
 import org.apache.geode.test.junit.rules.GfshCommandRule;
+import org.apache.geode.test.junit.rules.RequiresGeodeHome;
 
 /**
  * Setup class for Tomcat Client Server tests
  *
  * Sets up the server needed for the client container to connect to
  */
-public abstract class TomcatClientServerTest extends CargoTestBase {
-  private String serverName1;
-  private String serverName2;
+public abstract class TomcatClientServerTest extends TomcatTest {
+  private final ArrayList<String> serverList = new ArrayList<>();
+  private final int numberOfServers = 2;
 
   @Rule
   public transient TemporaryFolder temporaryFolder = new TemporaryFolder();
@@ -41,16 +45,38 @@ public abstract class TomcatClientServerTest extends 
CargoTestBase {
   @Rule
   public transient GfshCommandRule gfsh = new GfshCommandRule();
 
+  @Rule
+  public RequiresGeodeHome requiresGeodeHome = new RequiresGeodeHome();
+
   /**
    * Starts a server for the client Tomcat container to connect to using the 
GFSH command line
    * before each test
    */
   @Before
   public void startServer() throws Exception {
-    serverName1 = startAServer(1);
-    serverName2 = startAServer(2);
+    for (int i = 0; i < numberOfServers; i++) {
+      serverList.add(startAServer(i));
+    }
 
     afterStartServers();
+
+    if (isCachingClient()) {
+      deployJars();
+    }
+  }
+
+  private void deployJars() throws Exception {
+    String currentVersion = Version.CURRENT.getName();
+
+    String geodeHome = requiresGeodeHome.getGeodeHome().getAbsolutePath();
+    int index = geodeHome.indexOf("geode-assembly");
+    geodeHome = geodeHome.substring(0, index);
+    String fileName = geodeHome + 
"extensions/session-testing-war/build/libs/session-testing-war-"
+        + currentVersion + "-SNAPSHOT.jar";
+    CommandStringBuilder command = new CommandStringBuilder(CliStrings.DEPLOY);
+    command.addOption(CliStrings.JAR, fileName);
+    gfsh.connectAndVerify(locatorVM.getPort(), 
GfshCommandRule.PortType.locator);
+    gfsh.executeAndAssertThat(command.toString()).statusIsSuccess();
   }
 
   public void afterStartServers() throws Exception {}
@@ -73,7 +99,13 @@ public abstract class TomcatClientServerTest extends 
CargoTestBase {
         binDirJars + File.pathSeparator + libDirJars);
     command.addOption(CliStrings.START_SERVER__LOCATORS,
         locatorVM.invoke(() -> ClusterStartupRule.getLocator().asString()));
+    // statistic file
+    command.addOption(CliStrings.START_SERVER__STATISTIC_ARCHIVE_FILE, 
"statArchive.gfs");
+
     command.addOption(CliStrings.START_SERVER__J, 
"-Dgemfire.member-timeout=60000");
+    command.addOption(CliStrings.START_SERVER__J, 
"-Dgemfire.statistic-sampling-enabled=true");
+    command.addOption(CliStrings.START_SERVER__J, 
"-XX:+HeapDumpOnOutOfMemoryError");
+    command.addOption(CliStrings.START_SERVER__J, 
"-XX:+JavaMonitorsInStackTrace");
 
     // Start server
     gfsh.executeAndAssertThat(command.toString()).statusIsSuccess();
@@ -85,9 +117,13 @@ public abstract class TomcatClientServerTest extends 
CargoTestBase {
    * Stops the server for the client Tomcat container is has been connecting to
    */
   @After
-  public void stopServer() throws Exception {
-    stopAServer(serverName1);
-    stopAServer(serverName2);
+  public void stopServer() {
+    for (int i = 0; i < numberOfServers; i++) {
+      try {
+        stopAServer(serverList.get(i));
+      } catch (Exception ignore) {
+      }
+    }
   }
 
   private void stopAServer(String serverName) {
diff --git 
a/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/TomcatTest.java
 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/TomcatTest.java
new file mode 100644
index 0000000..01bf0ef
--- /dev/null
+++ 
b/geode-assembly/src/distributedTest/java/org/apache/geode/session/tests/TomcatTest.java
@@ -0,0 +1,267 @@
+/*
+ * 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 java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+import org.apache.geode.logging.internal.log4j.api.LogService;
+import org.apache.geode.test.junit.rules.ExecutorServiceRule;
+
+public abstract class TomcatTest extends CargoTestBase {
+  @Rule
+  public ExecutorServiceRule executorServiceRule = new ExecutorServiceRule();
+
+  @Rule
+  public ErrorCollector errorCollector = new ErrorCollector();
+
+  protected int numberOfConcurrentClients;
+  protected CountDownLatch latch;
+  protected CountDownLatch finishLatch;
+  protected CountDownLatch checkQueueLatch;
+  private final Random random = new Random();
+  private final Map<Client, HashMap<String, String>> clientAttributesMap =
+      new ConcurrentHashMap<>();
+  private int counter = 0;
+
+  @Test
+  public void multipleClientsCanMaintainOwnSessions() throws Throwable {
+    dumpLogs = false;
+    numberOfConcurrentClients = 20;
+    latch = new CountDownLatch(numberOfConcurrentClients);
+    finishLatch = new CountDownLatch(numberOfConcurrentClients);
+    checkQueueLatch = new CountDownLatch(1);
+    manager.startAllInactiveContainers();
+    for (int i = 0; i < numberOfConcurrentClients; i++) {
+      executorServiceRule.submit(() -> doSessionOps(20));
+    }
+    if (isCachingClient()) {
+      waitUntilHARegionQueueAreDrainedOnAllServers();
+    }
+    finishLatch.await();
+  }
+
+  protected void doSessionOps(int maxNumOfOperations) throws Exception {
+    String key = "key";
+    String value = "Foo55";
+    String key1 = "key1";
+    String value1 = "Bar1226";
+
+    Client client = new Client();
+    int operatingContainer = random.nextInt(numberOfContainers);
+    try {
+      
client.setPort(Integer.parseInt(manager.getContainerPort(operatingContainer)));
+      LogService.getLogger().info(
+          "doing work for client " + client + " on Container 
operatingContainer "
+              + operatingContainer);
+      LogService.getLogger().info("putting key " + key + " value " + value);
+      Client.Response resp = client.set(key, value);
+      // To reproduce GEODE-7780 uncomment out the following code
+      // if (operatingContainer == 0) {
+      // getKeyValueDataOnOperatingClient(client, key, value, 
resp.getSessionCookie(), 1);
+      // } else {
+      // getKeyValueDataOnOperatingClient(client, key, value, 
resp.getSessionCookie(), 0);
+      // }
+      if (isCachingClient()) {
+        // assume sticky session for client with caching proxy
+        getKeyValueDataOnOperatingClient(client, key, value, 
resp.getSessionCookie(),
+            operatingContainer);
+      } else {
+        getKeyValueDataOnAllClients(client, key, value, 
resp.getSessionCookie());
+      }
+      resp = client.set(key1, value1);
+      if (isCachingClient()) {
+        getKeyValueDataOnOperatingClient(client, key1, value1, 
resp.getSessionCookie(),
+            operatingContainer);
+      } else {
+        getKeyValueDataOnAllClients(client, key1, value1, 
resp.getSessionCookie());
+      }
+      resp = client.set(key, null);
+      if (isCachingClient()) {
+        getKeyValueDataOnOperatingClient(client, key, "", 
resp.getSessionCookie(),
+            operatingContainer);
+      } else {
+        getKeyValueDataOnAllClients(client, key, "", resp.getSessionCookie());
+      }
+      doSetsAndVerifyGets(client, maxNumOfOperations, operatingContainer);
+    } catch (Throwable e) {
+      errorCollector.addError(e);
+    } finally {
+      latch.countDown();
+    }
+
+    if (isCachingClient()) {
+      checkQueueLatch.await();
+    }
+
+    try {
+      verifySessionAllAttributes(client, clientAttributesMap.get(client), 
client.get(key, true));
+    } catch (Throwable e) {
+      errorCollector.addError(e);
+    } finally {
+      finishLatch.countDown();
+    }
+  }
+
+  private void waitUntilHARegionQueueAreDrainedOnAllServers() throws Exception 
{
+    latch.await();
+    for (int i = 0; i < manager.numContainers(); i++) {
+      client.setPort(Integer.parseInt(manager.getContainerPort(i)));
+      LogService.getLogger().info("waitForQueueToDrain on container " + i);
+      client.waitForQueueToDrain();
+      LogService.getLogger().info("done waitForQueueToDrain on container " + 
i);
+    }
+    checkQueueLatch.countDown();
+  }
+
+  private synchronized void updateDoneCounter() {
+    ++counter;
+    LogService.getLogger().info("finished {} of sessions", counter);
+  }
+
+  private void doSetsAndVerifyGets(Client client, int maxNumberOfOperations, 
int operatingContainer)
+      throws Exception {
+    HashMap<String, String> attributes = new HashMap();
+    clientAttributesMap.put(client, attributes);
+
+    int numberOfOperations = random.nextInt(maxNumberOfOperations) + 1;
+    LogService.getLogger().info("performing {} of operations", 
numberOfOperations);
+    for (int i = 0; i < numberOfOperations; i++) {
+      if (i % 2 == 0) {
+        doGetsAndSets(client, attributes, operatingContainer);
+      } else {
+        doSetsAndGetWithUpdate(client, attributes, operatingContainer);
+      }
+    }
+    LogService.getLogger().info("finished doSetsAndVerifyGets ops for {} 
times",
+        numberOfOperations);
+    updateDoneCounter();
+  }
+
+  private void doGetsAndSets(Client client, HashMap<String, String> attributes,
+      int operatingContainer)
+      throws IOException, URISyntaxException {
+    String key = getKey(client, attributes);
+    int maxLength = 100;
+    String value = getRandomVarChar(client, attributes, maxLength);
+    attributes.put(key, value);
+    verifySets(client, attributes, operatingContainer, key, value);
+  }
+
+  private void verifySets(Client client, HashMap<String, String> attributes, 
int operatingContainer,
+      String key, String value) throws IOException, URISyntaxException {
+    int whichContainer =
+        isCachingClient() ? operatingContainer : 
random.nextInt(numberOfContainers);
+    client.setPort(Integer.parseInt(manager.getContainerPort(whichContainer)));
+    Client.Response resp = client.set(key, value);
+    if (isCachingClient()) {
+      getKeyValueDataOnOperatingClient(client, key, value, 
resp.getSessionCookie(),
+          operatingContainer);
+      verifySessionGets(client, attributes, resp, operatingContainer);
+    } else {
+      getKeyValueDataOnAllClients(client, key, value, resp.getSessionCookie());
+      verifySessionGets(client, attributes, resp);
+    }
+  }
+
+  private void doSetsAndGetWithUpdate(Client client, HashMap<String, String> 
attributes,
+      int operatingContainer)
+      throws IOException, URISyntaxException {
+    String key = getKey(client, attributes);
+    if (random.nextInt(10) == 1) {
+      // do update on an existing attribute
+      key = "key";
+    }
+    int maxLength = 100;
+    String value = getRandomVarChar(client, attributes, maxLength);
+    attributes.put(key, value);
+    verifySets(client, attributes, operatingContainer, key, value);
+  }
+
+  protected String getKey(Client client, Map attributes) {
+    return "key" + (attributes.size() + 1) + "_" + client.getCookie();
+  }
+
+  protected String getRandomVarChar(Client client, Map attributes, int length) 
{
+    if (length == 0) {
+      return "";
+    }
+    StringBuffer buffer = new StringBuffer();
+    buffer.append("value" + (attributes.size() + 1) + "_" + 
client.getCookie());
+    int randomLength = random.nextInt(length) + 1;
+
+    int sp = ' ';
+    int tilde = '~';
+    for (int j = 0; j < randomLength; j++) {
+      buffer.append((char) (random.nextInt(tilde - sp) + sp));
+    }
+    return buffer.toString();
+  }
+
+  private void verifySessionGets(Client client, HashMap<String, String> 
attributes,
+      Client.Response resp) throws IOException, URISyntaxException {
+    verifySessionGets(client, attributes, resp, -1);
+  }
+
+  private void verifySessionGets(Client client, HashMap<String, String> 
attributes,
+      Client.Response resp, int operatingContainer) throws IOException, 
URISyntaxException {
+    int count = 0;
+    int whichOne = random.nextInt(attributes.size());
+    Iterator iterator = attributes.entrySet().iterator();
+    while (iterator.hasNext()) {
+      Map.Entry entry = (Map.Entry) iterator.next();
+      if (count == whichOne) {
+        String key = (String) entry.getKey();
+        String expectedValue = (String) entry.getValue();
+        if (isCachingClient()) {
+          getKeyValueDataOnOperatingClient(client, key, expectedValue,
+              resp.getSessionCookie(), operatingContainer);
+        } else {
+          getKeyValueDataOnAllClients(client, key, expectedValue,
+              resp.getSessionCookie());
+        }
+        break;
+      }
+      count++;
+    }
+  }
+
+  private void verifySessionAllAttributes(Client client, HashMap<String, 
String> attributes,
+      Client.Response resp) throws IOException, URISyntaxException {
+    Iterator iterator = attributes.entrySet().iterator();
+    while (iterator.hasNext()) {
+      Map.Entry entry = (Map.Entry) iterator.next();
+      String key = (String) entry.getKey();
+      String expectedValue = (String) entry.getValue();
+      getKeyValueDataOnAllClients(client, key, expectedValue,
+          resp.getSessionCookie());
+    }
+  }
+
+  protected boolean isCachingClient() {
+    return install.getConnectionType() == 
ContainerInstall.ConnectionType.CACHING_CLIENT_SERVER;
+  }
+}

Reply via email to