package org.infinispan.server.memcached; import static org.infinispan.server.memcached.ConnectionStatsTest.testMultipleLocalConnections; import static org.infinispan.server.memcached.ConnectionStatsTest.testSingleLocalConnection; import static org.infinispan.server.memcached.test.MemcachedTestingUtil.createMemcachedClient; import static org.infinispan.test.TestingUtil.k; import static org.infinispan.test.TestingUtil.sleepThread; import static org.infinispan.test.TestingUtil.v; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotSame; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import java.io.IOException; import java.lang.reflect.Method; import java.net.SocketAddress; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.MalformedObjectNameException; import javax.management.ReflectionException; import org.infinispan.Version; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.test.fwk.TestCacheManagerFactory; import org.infinispan.test.fwk.TestResourceTracker; import org.jgroups.util.Triple; import org.testng.annotations.Test; import net.spy.memcached.CASValue; import net.spy.memcached.MemcachedClient; import net.spy.memcached.internal.OperationFuture; /** * Tests stats command for Infinispan Memcached server. * * @author Galder ZamarreƱo * @since 4.1 */ @Test(groups = "functional", testName = "server.memcached.MemcachedStatsTest") public class MemcachedStatsTest extends MemcachedSingleNodeTest { private static String jmxDomain = MemcachedStatsTest.class.getSimpleName(); @Override public EmbeddedCacheManager createTestCacheManager() { return TestCacheManagerFactory.createCacheManagerEnforceJmxDomain(jmxDomain); } public void testUnsupportedStats() { Triple<Map<String, String>, Integer, Integer> stats = getStats(-1, -1); assertEquals(stats.getVal1().get("pid"), "0"); assertEquals(stats.getVal1().get("pointer_size"), "0"); assertEquals(stats.getVal1().get("rusage_user"), "0"); assertEquals(stats.getVal1().get("rusage_system"), "0"); assertEquals(stats.getVal1().get("bytes"), "0"); assertEquals(stats.getVal1().get("connection_structures"), "0"); assertEquals(stats.getVal1().get("auth_cmds"), "0"); assertEquals(stats.getVal1().get("auth_errors"), "0"); assertEquals(stats.getVal1().get("limit_maxbytes"), "0"); assertEquals(stats.getVal1().get("conn_yields"), "0"); assertEquals(stats.getVal1().get("reclaimed"), "0"); } public void testUncomparableStats() { sleepThread(TimeUnit.SECONDS.toMillis(1)); Triple<Map<String, String>, Integer, Integer> stats = getStats(-1, -1); assertNotSame(stats.getVal1().get("uptime"), "0"); assertNotSame(stats.getVal1().get("time"), "0"); assertNotSame(stats.getVal1().get("uptime"), stats.getVal1().get("time")); } public void testStaticStats() { Triple<Map<String, String>, Integer, Integer> stats = getStats(-1, -1); assertEquals(stats.getVal1().get("version"), Version.getVersion()); } public void testTodoStats() { Triple<Map<String, String>, Integer, Integer> stats = getStats(-1, -1); assertEquals(stats.getVal1().get("curr_connections"), "0"); assertEquals(stats.getVal1().get("total_connections"), "0"); assertEquals(stats.getVal1().get("threads"), "0"); } public void testStats(Method m) throws InterruptedException, ExecutionException, TimeoutException { Triple<Map<String, String>, Integer, Integer> stats = getStats(-1, -1); assertEquals(stats.getVal1().get("cmd_set"), "0"); assertEquals(stats.getVal1().get("cmd_get"), "0"); assertEquals(stats.getVal1().get("get_hits"), "0"); assertEquals(stats.getVal1().get("get_misses"), "0"); assertEquals(stats.getVal1().get("delete_hits"), "0"); assertEquals(stats.getVal1().get("delete_misses"), "0"); assertEquals(stats.getVal1().get("curr_items"), "0"); assertEquals(stats.getVal1().get("total_items"), "0"); assertEquals(stats.getVal1().get("incr_misses"), "0"); assertEquals(stats.getVal1().get("incr_hits"), "0"); assertEquals(stats.getVal1().get("decr_misses"), "0"); assertEquals(stats.getVal1().get("decr_hits"), "0"); assertEquals(stats.getVal1().get("cas_misses"), "0"); assertEquals(stats.getVal1().get("cas_hits"), "0"); assertEquals(stats.getVal1().get("cas_badval"), "0"); OperationFuture<Boolean> f = client.set(k(m), 0, v(m)); assertTrue(f.get(timeout, TimeUnit.SECONDS)); assertEquals(client.get(k(m)), v(m)); f = client.set(k(m, "k1-"), 0, v(m, "v1-")); assertTrue(f.get(timeout, TimeUnit.SECONDS)); assertEquals(client.get(k(m, "k1-")), v(m, "v1-")); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("cmd_set"), "2"); assertEquals(stats.getVal1().get("cmd_get"), "2"); assertEquals(stats.getVal1().get("get_hits"), "2"); assertEquals(stats.getVal1().get("get_misses"), "0"); assertEquals(stats.getVal1().get("delete_hits"), "0"); assertEquals(stats.getVal1().get("delete_misses"), "0"); assertEquals(stats.getVal1().get("curr_items"), "2"); assertEquals(stats.getVal1().get("total_items"), "2"); f = client.delete(k(m, "k1-")); assertTrue(f.get(timeout, TimeUnit.SECONDS)); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("curr_items"), "1"); assertEquals(stats.getVal1().get("total_items"), "2"); assertEquals(stats.getVal1().get("delete_hits"), "1"); assertEquals(stats.getVal1().get("delete_misses"), "0"); assertNull(client.get(k(m, "k99-"))); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("get_hits"), "2"); assertEquals(stats.getVal1().get("get_misses"), "1"); f = client.delete(k(m, "k99-")); assertFalse(f.get(timeout, TimeUnit.SECONDS)); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("delete_hits"), "1"); assertEquals(stats.getVal1().get("delete_misses"), "1"); int future = (int) TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() + 1000); f = client.set(k(m, "k3-"), future, v(m, "v3-")); assertTrue(f.get(timeout, TimeUnit.SECONDS)); sleepThread(1100); assertNull(client.get(k(m, "k3-"))); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("curr_items"), "1"); assertEquals(stats.getVal1().get("total_items"), "3"); client.incr(k(m, "k4-"), 1); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("incr_misses"), "1"); assertEquals(stats.getVal1().get("incr_hits"), "0"); f = client.set(k(m, "k4-"), 0, "1"); assertTrue(f.get(timeout, TimeUnit.SECONDS)); client.incr(k(m, "k4-"), 1); client.incr(k(m, "k4-"), 2); client.incr(k(m, "k4-"), 4); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("incr_misses"), "1"); assertEquals(stats.getVal1().get("incr_hits"), "3"); client.decr(k(m, "k5-"), 1); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("decr_misses"), "1"); assertEquals(stats.getVal1().get("decr_hits"), "0"); f = client.set(k(m, "k5-"), 0, "8"); assertTrue(f.get(timeout, TimeUnit.SECONDS)); client.decr(k(m, "k5-"), 1); client.decr(k(m, "k5-"), 2); client.decr(k(m, "k5-"), 4); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("decr_misses"), "1"); assertEquals(stats.getVal1().get("decr_hits"), "3"); client.cas(k(m, "k6-"), 1234, v(m, "v6-")); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("cas_misses"), "1"); assertEquals(stats.getVal1().get("cas_hits"), "0"); assertEquals(stats.getVal1().get("cas_badval"), "0"); f = client.set(k(m, "k6-"), 0, v(m, "v6-")); assertTrue(f.get(timeout, TimeUnit.SECONDS)); CASValue value = client.gets(k(m, "k6-")); long old = value.getCas(); client.cas(k(m, "k6-"), value.getCas(), v(m, "v66-")); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("cas_misses"), "1"); assertEquals(stats.getVal1().get("cas_hits"), "1"); assertEquals(stats.getVal1().get("cas_badval"), "0"); client.cas(k(m, "k6-"), old, v(m, "v66-")); stats = getStats(stats.getVal2(), stats.getVal3()); assertEquals(stats.getVal1().get("cas_misses"), "1"); assertEquals(stats.getVal1().get("cas_hits"), "1"); assertEquals(stats.getVal1().get("cas_badval"), "1"); } private List<MemcachedClient> createMultipleClients(List<MemcachedClient> clients, int number, int from) throws IOException { if (from >= number) return clients; else { MemcachedClient newClient = createMemcachedClient(60000, server.getPort()); Object value = newClient.get("a"); // 'Use' the value if (value != null && value.hashCode() % 1000 == 0) { System.out.print(value.hashCode()); } clients.add(newClient); return createMultipleClients(clients, number, from + 1); } } public void testStatsSpecificToMemcachedViaJmx() throws MalformedObjectNameException, AttributeNotFoundException, MBeanException, ReflectionException, InstanceNotFoundException, IOException { // Send any command getStats(-1, -1); String serverName = "Memcached-" + TestResourceTracker.getCurrentTestShortName(); testSingleLocalConnection(jmxDomain, serverName); List<MemcachedClient> clients = new ArrayList<>(); try { clients = createMultipleClients(clients, 10, 0); testMultipleLocalConnections(jmxDomain, serverName, clients.size() + 1); } finally { clients.forEach(client -> { try { client.shutdown(20, TimeUnit.SECONDS); } catch (Throwable t) { } // Ignore it... }); } } public void testStatsWithArgs() throws IOException { String resp = send("stats\r\n"); assertExpectedResponse(resp, "STAT", false); resp = send("stats \r\n"); assertExpectedResponse(resp, "STAT", false); resp = send("stats boo\r\n"); assertClientError(resp); resp = send("stats boo boo2 boo3\r\n"); assertClientError(resp); } private Triple<Map<String, String>, Integer, Integer> getStats(int currentBytesRead, int currentBytesWritten) { Map<SocketAddress, Map<String, String>> globalStats = client.getStats(); assertEquals(globalStats.size(), 1); Map<String, String> stats = globalStats.values().iterator().next(); int bytesRead = assertHigherBytes(currentBytesRead, stats.get("bytes_read")); int bytesWritten = assertHigherBytes(currentBytesRead, stats.get("bytes_written")); return new Triple(stats, bytesRead, bytesWritten); } private int assertHigherBytes(int currentBytesRead, String bytesStr) { int bytesRead = Integer.parseInt(bytesStr); assertTrue(bytesRead > currentBytesRead); return bytesRead; } }