You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by bs...@apache.org on 2020/04/14 18:30:00 UTC

[geode] 01/01: GEODE-7852: test ClientHealthMonitor functionality behind a SNI gateway

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

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

commit 376df4cc7abc6db38b4b298f8af6f3c53baedf15
Author: Bruce Schuchardt <bs...@pivotal.io>
AuthorDate: Tue Apr 14 10:55:56 2020 -0700

    GEODE-7852: test ClientHealthMonitor functionality behind a SNI gateway
    
    This ensures that a server sitting behind an SNI gateway detects the
    loss of a client and cleans up after it.  In this case the test detects
    that the server has closed CQs created by the non-durable client.
    
    Since test code is not accessible in the Docker container that's running
    the server I've enhanced the StatArchiveReader to be able to report the
    values of a statistic and have enabled statistics recording in the
    server.
---
 .../client/sni/ClientSNICQAcceptanceTest.java      |  34 +++++-
 .../client/sni/geode-config/gemfire.properties     |   3 +-
 .../internal/statistics/StatArchiveReader.java     | 114 +++++++++++++++++++--
 3 files changed, 140 insertions(+), 11 deletions(-)

diff --git a/geode-assembly/src/acceptanceTest/java/org/apache/geode/client/sni/ClientSNICQAcceptanceTest.java b/geode-assembly/src/acceptanceTest/java/org/apache/geode/client/sni/ClientSNICQAcceptanceTest.java
index d422807..33a4320 100644
--- a/geode-assembly/src/acceptanceTest/java/org/apache/geode/client/sni/ClientSNICQAcceptanceTest.java
+++ b/geode-assembly/src/acceptanceTest/java/org/apache/geode/client/sni/ClientSNICQAcceptanceTest.java
@@ -22,6 +22,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_
 import static org.apache.geode.distributed.ConfigurationProperties.SSL_REQUIRE_AUTHENTICATION;
 import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE;
 import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD;
+import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
 import static org.apache.geode.test.util.ResourceUtils.createTempFileFromResource;
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -31,6 +32,7 @@ import java.util.Properties;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import com.palantir.docker.compose.DockerComposeRule;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
@@ -42,6 +44,7 @@ import org.apache.geode.cache.Region;
 import org.apache.geode.cache.client.ClientCache;
 import org.apache.geode.cache.client.ClientCacheFactory;
 import org.apache.geode.cache.client.ClientRegionShortcut;
+import org.apache.geode.cache.client.internal.PoolImpl;
 import org.apache.geode.cache.client.proxy.ProxySocketFactories;
 import org.apache.geode.cache.query.CqAttributes;
 import org.apache.geode.cache.query.CqAttributesFactory;
@@ -72,6 +75,7 @@ public class ClientSNICQAcceptanceTest {
 
   AtomicInteger eventCreateCounter = new AtomicInteger(0);
   AtomicInteger eventUpdateCounter = new AtomicInteger(0);
+  private ClientCache cache;
 
   class SNICQListener implements CqListener {
 
@@ -107,9 +111,18 @@ public class ClientSNICQAcceptanceTest {
 
   }
 
+  @After
+  public void after() throws Exception {
+    String output =
+        docker.exec(options("-T"), "geode", arguments("cat", "server-dolores/server-dolores.log"));
+    System.out.println("Server log file--------------------------------\n" + output);
+    if (cache != null) {
+      cache.close();
+    }
+  }
+
   @Test
-  public void performSimpleCQOverSNIProxy()
-      throws CqException, CqExistsException, RegionNotFoundException {
+  public void performSimpleCQOverSNIProxy() throws Exception {
     Properties gemFireProps = new Properties();
     gemFireProps.setProperty(SSL_ENABLED_COMPONENTS, "all");
     gemFireProps.setProperty(SSL_KEYSTORE_TYPE, "jks");
@@ -123,7 +136,7 @@ public class ClientSNICQAcceptanceTest {
         .container("haproxy")
         .port(15443)
         .getExternalPort();
-    ClientCache cache = new ClientCacheFactory(gemFireProps)
+    cache = new ClientCacheFactory(gemFireProps)
         .addPoolLocator("locator-maeve", 10334)
         .setPoolSocketFactory(ProxySocketFactories.sni("localhost",
             proxyPort))
@@ -152,6 +165,21 @@ public class ClientSNICQAcceptanceTest {
 
     assertThat(eventUpdateCounter.get()).isEqualTo(62);
 
+    // verify that the server cleans up when the client connection to the gateway is destroyed
+    ((PoolImpl) cache.getDefaultPool()).killPrimaryEndpoint();
+    // since we can't run code in the server let's grab the CQ statistics and verify that
+    // the CQ has been closed. StatArchiveReader has a main() that we can use to get a printout
+    // of stat values
+    await().untilAsserted(() -> {
+      String stats = docker.exec(options("-T"), "geode",
+          arguments("java", "-cp", "/geode/lib/geode-dependencies.jar",
+              "org.apache.geode.internal.statistics.StatArchiveReader",
+              "stat", "server-dolores/statArchive.gfs", "CqServiceStats.numCqsClosed"));
+      System.out.println("stats from server are :" + stats);
+      // the stat should transition from zero to one at some point
+      assertThat(stats).contains("0.0 1.0");
+    });
+
   }
 
   public void updateRegion(Region<String, Integer> region) {
diff --git a/geode-assembly/src/acceptanceTest/resources/org/apache/geode/client/sni/geode-config/gemfire.properties b/geode-assembly/src/acceptanceTest/resources/org/apache/geode/client/sni/geode-config/gemfire.properties
index 213cabe..1f13fb0 100644
--- a/geode-assembly/src/acceptanceTest/resources/org/apache/geode/client/sni/geode-config/gemfire.properties
+++ b/geode-assembly/src/acceptanceTest/resources/org/apache/geode/client/sni/geode-config/gemfire.properties
@@ -15,4 +15,5 @@
 # limitations under the License.
 #
 
-#empty
+statistic-sampling-enabled=true
+statistic-archive-file=statArchive.gfs
diff --git a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveReader.java b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveReader.java
index 25670c3..a62e311 100644
--- a/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveReader.java
+++ b/geode-core/src/main/java/org/apache/geode/internal/statistics/StatArchiveReader.java
@@ -210,21 +210,121 @@ public class StatArchiveReader implements StatArchiveFormat, AutoCloseable {
     }
   }
 
+  private static class SingleStatRawStatSpec implements StatSpec {
+
+    private final String archive;
+    private final String statType;
+    private final String statName;
+
+    SingleStatRawStatSpec(String archive, String typeAndStat) {
+      this.archive = archive;
+      String[] parts = typeAndStat.split("\\.", 0);
+      this.statType = parts[0];
+      this.statName = parts[1];
+    }
+
+    @Override
+    public boolean archiveMatches(File archive) {
+      return true; // this.archive.equalsIgnoreCase(archive.getName());
+    }
+
+    @Override
+    public boolean typeMatches(String typeName) {
+      return this.statType.equalsIgnoreCase(typeName);
+    }
+
+    @Override
+    public boolean statMatches(String statName) {
+      return this.statName.equalsIgnoreCase(statName);
+    }
+
+    @Override
+    public boolean instanceMatches(String textId, long numericId) {
+      return true;
+    }
+
+    @Override
+    public int getCombineType() {
+      return StatSpec.NONE;
+    }
+  }
+
+  private static void printStatValue(StatArchiveReader.StatValue v, long startTime, long endTime,
+      boolean nofilter, boolean persec, boolean persample, boolean prunezeros, boolean details) {
+    v = v.createTrimmed(startTime, endTime);
+    if (nofilter) {
+      v.setFilter(StatArchiveReader.StatValue.FILTER_NONE);
+    } else if (persec) {
+      v.setFilter(StatArchiveReader.StatValue.FILTER_PERSEC);
+    } else if (persample) {
+      v.setFilter(StatArchiveReader.StatValue.FILTER_PERSAMPLE);
+    }
+    if (prunezeros) {
+      if (v.getSnapshotsMinimum() == 0.0 && v.getSnapshotsMaximum() == 0.0) {
+        return;
+      }
+    }
+    System.out.println("  " + v.toString());
+    if (details) {
+      System.out.print("  values=");
+      double[] snapshots = v.getSnapshots();
+      for (int i = 0; i < snapshots.length; i++) {
+        System.out.print(' ');
+        System.out.print(snapshots[i]);
+      }
+      System.out.println();
+      String desc = v.getDescriptor().getDescription();
+      if (desc != null && desc.length() > 0) {
+        System.out.println("    " + desc);
+      }
+    }
+  }
+
+
   /**
    * Simple utility to read and dump statistic archive.
    */
   public static void main(String args[]) throws IOException {
     String archiveName = null;
+    final StatArchiveReader reader;
     if (args.length > 1) {
-      System.err.println("Usage: [archiveName]");
-      ExitCode.FATAL.doSystemExit();
-    } else if (args.length == 1) {
-      archiveName = args[0];
+      if (!args[0].equals("stat") || args.length > 3) {
+        System.err.println("Usage: stat archiveName statType.statName");
+        ExitCode.FATAL.doSystemExit();
+      }
+      archiveName = args[1];
+      String statSpec = args[2];
+      if (!statSpec.contains(".")) {
+        throw new IllegalArgumentException(
+            "stat spec '" + statSpec + "' is malformed - use StatType.statName");
+      }
+      File archiveFile = new File(archiveName);
+      if (!archiveFile.exists()) {
+        throw new IllegalArgumentException("archive file does not exist: " + archiveName);
+      }
+      if (!archiveFile.canRead()) {
+        throw new IllegalArgumentException("archive file exists but is unreadable: " + archiveName);
+      }
+      File[] archives = new File[] {archiveFile};
+      SingleStatRawStatSpec[] filters =
+          new SingleStatRawStatSpec[] {new SingleStatRawStatSpec(archiveName, args[2])};
+      reader = new StatArchiveReader(archives, filters, false);
+      final StatValue[] statValues = reader.matchSpec(filters[0]);
+      System.out.println(statSpec + " matched " + statValues.length + " stats...");
+      for (StatValue value : statValues) {
+        printStatValue(value, -1, -1, true, false, false, false, true);
+      }
+      System.out.println("");
+      System.out.flush();
     } else {
-      archiveName = "statArchive.gfs";
+      if (args.length == 1) {
+        archiveName = args[0];
+      } else {
+        archiveName = "statArchive.gfs";
+      }
+      reader = new StatArchiveReader(archiveName);
+      System.out.println("DEBUG: memory used = " + reader.getMemoryUsed());
     }
-    StatArchiveReader reader = new StatArchiveReader(archiveName);
-    System.out.println("DEBUG: memory used = " + reader.getMemoryUsed());
     reader.close();
   }