/* * 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.management; import static org.apache.geode.distributed.ConfigurationProperties.*; import static org.apache.geode.test.dunit.Assert.*; import java.util.Collection; import java.util.Iterator; import java.util.Properties; import org.junit.Test; import org.junit.experimental.categories.Category; import org.apache.geode.cache.Cache; import org.apache.geode.cache.EntryEvent; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionFactory; import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.cache.client.ClientRegionFactory; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.server.CacheServer; import org.apache.geode.cache.util.CacheListenerAdapter; import org.apache.geode.distributed.DistributedMember; import org.apache.geode.internal.cache.GemFireCacheImpl; import org.apache.geode.internal.cache.tier.sockets.CacheClientNotifier; import org.apache.geode.internal.cache.tier.sockets.CacheClientProxy; import org.apache.geode.internal.i18n.LocalizedStrings; import org.apache.geode.test.dunit.Host; import org.apache.geode.test.dunit.IgnoredException; import org.apache.geode.test.dunit.VM; import org.apache.geode.test.dunit.Wait; import org.apache.geode.test.dunit.WaitCriterion; import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase; import org.apache.geode.test.junit.categories.DistributedTest; import org.apache.geode.test.junit.categories.FlakyTest; /** * Client health stats check */ @Category(DistributedTest.class) @SuppressWarnings("serial") public class ClientHealthStatsDUnitTest extends JUnit4DistributedTestCase { private static final String k1 = "k1"; private static final String k2 = "k2"; private static final String client_k1 = "client-k1"; private static final String client_k2 = "client-k2"; /** name of the test region */ private static final String REGION_NAME = "ClientHealthStatsDUnitTest_Region"; private static VM client = null; private static VM client2 = null; private static VM managingNode = null; private static ManagementTestBase helper = new ManagementTestBase() {}; private static int numOfCreates = 0; private static int numOfUpdates = 0; private static int numOfInvalidates = 0; private static boolean lastKeyReceived = false; private static GemFireCacheImpl cache = null; private VM server = null; @Override public final void postSetUp() throws Exception { disconnectAllFromDS(); final Host host = Host.getHost(0); managingNode = host.getVM(0); server = host.getVM(1); client = host.getVM(2); client2 = host.getVM(3); IgnoredException.addIgnoredException("Connection reset"); } @Override public final void preTearDown() throws Exception { reset(); helper.closeCache(managingNode); helper.closeCache(client); helper.closeCache(client2); helper.closeCache(server); disconnectAllFromDS(); } private static void reset() throws Exception { lastKeyReceived = false; numOfCreates = 0; numOfUpdates = 0; numOfInvalidates = 0; } @Test public void testClientHealthStats_SubscriptionEnabled() throws Exception { helper.createManagementCache(managingNode); helper.startManagingNode(managingNode); int port = (Integer) server.invoke(() -> ClientHealthStatsDUnitTest.createServerCache()); DistributedMember serverMember = helper.getMember(server); client.invoke( () -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 1, true, false)); client2.invoke( () -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 2, true, false)); client.invoke(() -> ClientHealthStatsDUnitTest.put()); client2.invoke(() -> ClientHealthStatsDUnitTest.put()); managingNode.invoke(() -> ClientHealthStatsDUnitTest.verifyClientStats(serverMember, port, 2)); helper.stopManagingNode(managingNode); } @Test public void testClientHealthStats_SubscriptionDisabled() throws Exception { helper.createManagementCache(managingNode); helper.startManagingNode(managingNode); int port = (Integer) server.invoke(() -> ClientHealthStatsDUnitTest.createServerCache()); DistributedMember serverMember = helper.getMember(server); client.invoke(() -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 1, false, false)); client2.invoke(() -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 2, false, false)); client.invoke(() -> ClientHealthStatsDUnitTest.put()); client2.invoke(() -> ClientHealthStatsDUnitTest.put()); managingNode.invoke(() -> ClientHealthStatsDUnitTest.verifyClientStats(serverMember, port, 0)); helper.stopManagingNode(managingNode); } @Test public void testClientHealthStats_DurableClient() throws Exception { helper.createManagementCache(managingNode); helper.startManagingNode(managingNode); int port = (Integer) server.invoke(() -> ClientHealthStatsDUnitTest.createServerCache()); DistributedMember serverMember = helper.getMember(server); client.invoke( () -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 1, true, true)); client2.invoke( () -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 2, true, true)); client.invoke(() -> ClientHealthStatsDUnitTest.put()); client2.invoke(() -> ClientHealthStatsDUnitTest.put()); client.invoke(() -> ClientHealthStatsDUnitTest.closeClientCache()); client2.invoke(() -> ClientHealthStatsDUnitTest.closeClientCache()); managingNode.invoke(() -> ClientHealthStatsDUnitTest.verifyClientStats(serverMember, port, 2)); helper.stopManagingNode(managingNode); } @Category(FlakyTest.class) // GEODE-337 @Test public void testStatsMatchWithSize() throws Exception { // start a server int port = (Integer) server.invoke(() -> ClientHealthStatsDUnitTest.createServerCache()); // create durable client, with durable RI client.invoke( () -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 1, true, false)); // do puts on server from three different threads, pause after 500 puts each. server.invoke(() -> ClientHealthStatsDUnitTest.doPuts()); // close durable client client.invoke(() -> ClientHealthStatsDUnitTest.closeClientCache()); server.invoke("verifyProxyHasBeenPaused", () -> verifyProxyHasBeenPaused()); // resume puts on server, add another 100. server.invokeAsync(() -> ClientHealthStatsDUnitTest.resumePuts()); // start durable client client.invoke( () -> ClientHealthStatsDUnitTest.createClientCache(server.getHost(), port, 1, true, false)); // wait for full queue dispatch client.invoke(() -> ClientHealthStatsDUnitTest.waitForLastKey()); // verify the stats server.invoke(() -> ClientHealthStatsDUnitTest.verifyStats(port)); } private static void verifyProxyHasBeenPaused() { WaitCriterion criterion = new WaitCriterion() { @Override public boolean done() { CacheClientNotifier ccn = CacheClientNotifier.getInstance(); Collection<CacheClientProxy> ccProxies = ccn.getClientProxies(); Iterator<CacheClientProxy> itr = ccProxies.iterator(); while (itr.hasNext()) { CacheClientProxy ccp = itr.next(); System.out.println("proxy status " + ccp.getState()); if (ccp.isPaused()) return true; } return false; } @Override public String description() { return "Proxy has not paused yet"; } }; Wait.waitForCriterion(criterion, 15 * 1000, 200, true); } private static int createServerCache() throws Exception { Cache cache = helper.createCache(false); RegionFactory<String, String> rf = cache.createRegionFactory(RegionShortcut.REPLICATE); rf.setConcurrencyChecksEnabled(false); rf.create(REGION_NAME); CacheServer server1 = cache.addCacheServer(); server1.setPort(0); server1.start(); return server1.getPort(); } private static void closeClientCache() throws Exception { cache.close(true); } private static void createClientCache(Host host, Integer port, int clientNum, boolean subscriptionEnabled, boolean durable) throws Exception { Properties props = new Properties(); props.setProperty(DURABLE_CLIENT_ID, "durable-" + clientNum); props.setProperty(DURABLE_CLIENT_TIMEOUT, "300000"); props.setProperty(LOG_LEVEL, "info"); props.setProperty(STATISTIC_ARCHIVE_FILE, getTestMethodName() + "_client_" + clientNum + ".gfs"); props.setProperty(STATISTIC_SAMPLING_ENABLED, "true"); ClientCacheFactory ccf = new ClientCacheFactory(props); if (subscriptionEnabled) { ccf.setPoolSubscriptionEnabled(true); ccf.setPoolSubscriptionAckInterval(50); ccf.setPoolSubscriptionRedundancy(0); } if (durable) { ccf.set(DURABLE_CLIENT_ID, "DurableClientId_" + clientNum); ccf.set(DURABLE_CLIENT_TIMEOUT, "" + 300); } ccf.addPoolServer(host.getHostName(), port); cache = (GemFireCacheImpl) ccf.create(); ClientRegionFactory<String, String> crf = cache.createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY); crf.setConcurrencyChecksEnabled(false); crf.addCacheListener(new CacheListenerAdapter<String, String>() { public void afterInvalidate(EntryEvent<String, String> event) { cache.getLoggerI18n() .fine("Invalidate Event: " + event.getKey() + ", " + event.getNewValue()); numOfInvalidates++; } public void afterCreate(EntryEvent<String, String> event) { if (((String) event.getKey()).equals("last_key")) { lastKeyReceived = true; } cache.getLoggerI18n().fine("Create Event: " + event.getKey() + ", " + event.getNewValue()); numOfCreates++; } public void afterUpdate(EntryEvent<String, String> event) { cache.getLoggerI18n().fine("Update Event: " + event.getKey() + ", " + event.getNewValue()); numOfUpdates++; } }); Region<String, String> r = crf.create(REGION_NAME); if (subscriptionEnabled) { r.registerInterest("ALL_KEYS", true); cache.readyForEvents(); } } private static void doPuts() throws Exception { Cache cache = GemFireCacheImpl.getInstance(); final Region<String, String> r = cache.getRegion(Region.SEPARATOR + REGION_NAME); Thread t1 = new Thread(new Runnable() { public void run() { for (int i = 0; i < 500; i++) { r.put("T1_KEY_" + i, "VALUE_" + i); } } }); Thread t2 = new Thread(new Runnable() { public void run() { for (int i = 0; i < 500; i++) { r.put("T2_KEY_" + i, "VALUE_" + i); } } }); Thread t3 = new Thread(new Runnable() { public void run() { for (int i = 0; i < 500; i++) { r.put("T3_KEY_" + i, "VALUE_" + i); } } }); t1.start(); t2.start(); t3.start(); t1.join(); t2.join(); t3.join(); } private static void resumePuts() { Cache cache = GemFireCacheImpl.getInstance(); Region<String, String> r = cache.getRegion(Region.SEPARATOR + REGION_NAME); for (int i = 0; i < 100; i++) { r.put("NEWKEY_" + i, "NEWVALUE_" + i); } r.put("last_key", "last_value"); } private static void waitForLastKey() { WaitCriterion wc = new WaitCriterion() { @Override public boolean done() { return lastKeyReceived; } @Override public String description() { return "Did not receive last key."; } }; Wait.waitForCriterion(wc, 60 * 1000, 500, true); } private static DistributedMember getMember() throws Exception { GemFireCacheImpl cache = GemFireCacheImpl.getInstance(); return cache.getDistributedSystem().getDistributedMember(); } private static void verifyClientStats(DistributedMember serverMember, int serverPort, int numSubscriptions) { GemFireCacheImpl cache = GemFireCacheImpl.getInstance(); try { ManagementService service = ManagementService.getExistingManagementService(cache); CacheServerMXBean bean = MBeanUtil.getCacheServerMbeanProxy(serverMember, serverPort); String[] clientIds = bean.getClientIds(); assertTrue(clientIds.length == 2); System.out.println( "<ExpectedString> ClientId-1 of the Server is " + clientIds[0] + "</ExpectedString> "); System.out.println( "<ExpectedString> ClientId-2 of the Server is " + clientIds[1] + "</ExpectedString> "); ClientHealthStatus[] clientStatuses = bean.showAllClientStats(); ClientHealthStatus clientStatus1 = bean.showClientStats(clientIds[0]); ClientHealthStatus clientStatus2 = bean.showClientStats(clientIds[1]); assertNotNull(clientStatus1); assertNotNull(clientStatus2); System.out.println("<ExpectedString> ClientStats-1 of the Server is " + clientStatus1 + "</ExpectedString> "); System.out.println("<ExpectedString> ClientStats-2 of the Server is " + clientStatus2 + "</ExpectedString> "); System.out .println("<ExpectedString> clientStatuses " + clientStatuses + "</ExpectedString> "); assertNotNull(clientStatuses); assertTrue(clientStatuses.length == 2); for (ClientHealthStatus status : clientStatuses) { System.out.println( "<ExpectedString> ClientStats of the Server is " + status + "</ExpectedString> "); } DistributedSystemMXBean dsBean = service.getDistributedSystemMXBean(); assertEquals(2, dsBean.getNumClients()); assertEquals(numSubscriptions, dsBean.getNumSubscriptions()); } catch (Exception e) { fail("Error while verifying cache server from remote member", e); } } private static void put() { Cache cache = GemFireCacheImpl.getInstance(); Region r1 = cache.getRegion(Region.SEPARATOR + REGION_NAME); assertNotNull(r1); r1.put(k1, client_k1); assertEquals(r1.getEntry(k1).getValue(), client_k1); r1.put(k2, client_k2); assertEquals(r1.getEntry(k2).getValue(), client_k2); try { Thread.sleep(10000); } catch (Exception e) { // sleep } r1.clear(); r1.put(k1, client_k1); assertEquals(r1.getEntry(k1).getValue(), client_k1); r1.put(k2, client_k2); assertEquals(r1.getEntry(k2).getValue(), client_k2); r1.clear(); try { Thread.sleep(10000); } catch (Exception e) { // sleep } } private static void verifyStats(int serverPort) throws Exception { Cache cache = GemFireCacheImpl.getInstance(); ManagementService service = ManagementService.getExistingManagementService(cache); CacheServerMXBean serverBean = service.getLocalCacheServerMXBean(serverPort); CacheClientNotifier ccn = CacheClientNotifier.getInstance(); CacheClientProxy ccp = ccn.getClientProxies().iterator().next(); cache.getLoggerI18n().info(LocalizedStrings.DEBUG, "getQueueSize() " + ccp.getQueueSize()); cache.getLoggerI18n().info(LocalizedStrings.DEBUG, "getQueueSizeStat() " + ccp.getQueueSizeStat()); cache.getLoggerI18n().info(LocalizedStrings.DEBUG, "getEventsEnqued() " + ccp.getHARegionQueue().getStatistics().getEventsEnqued()); cache.getLoggerI18n().info(LocalizedStrings.DEBUG, "getEventsDispatched() " + ccp.getHARegionQueue().getStatistics().getEventsDispatched()); cache.getLoggerI18n().info(LocalizedStrings.DEBUG, "getEventsRemoved() " + ccp.getHARegionQueue().getStatistics().getEventsRemoved()); cache.getLoggerI18n().info(LocalizedStrings.DEBUG, "getNumVoidRemovals() " + ccp.getHARegionQueue().getStatistics().getNumVoidRemovals()); assertEquals(ccp.getQueueSize(), ccp.getQueueSizeStat()); ClientQueueDetail queueDetails = serverBean.showClientQueueDetails()[0]; assertEquals(queueDetails.getQueueSize(), ccp.getQueueSizeStat()); } }