package org.infinispan.server.test.client.memcached; import static org.infinispan.server.test.util.ITestUtils.eventually; import static org.infinispan.server.test.util.ITestUtils.sleepForSecs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Map; import org.infinispan.Version; import org.infinispan.arquillian.core.RemoteInfinispanServer; import org.infinispan.commons.logging.Log; import org.infinispan.commons.logging.LogFactory; import org.infinispan.server.test.util.ITestUtils.Condition; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Tests for Memcached endpoint. Subclasses must provide a way to get the list of remote * infinispan servers. * <p/> * Subclasses may be used in Client-Server mode or Hybrid mode where Memcached server * runs as a library deployed in an application server. * * @author Michal Linhard * @author Martin Gencur * @author Jozef Vilkolak */ public abstract class AbstractMemcachedLocalIT { static final String ENCODING = "UTF-8"; // they are deleted in the setUp and tearDown methods static final String KEY_A = "a"; static final String KEY_B = "b"; static final String KEY_C = "c"; private static final Log log = LogFactory.getLog(AbstractMemcachedLocalIT.class); MemcachedClient mc; protected abstract RemoteInfinispanServer getServer(); protected abstract int getMemcachedPort(); public static class TestSerializable implements Serializable { private String content; public TestSerializable(String content) { super(); this.content = content; } public String getContent() { return content; } } @Before public void setUp() throws Exception { mc = new MemcachedClient(MemcachedSingleNodeDomainIT.ENCODING, getServer().getMemcachedEndpoint().getInetAddress() .getHostName(), getMemcachedPort(), 10000); mc.delete(KEY_A); mc.delete(KEY_B); mc.delete(KEY_C); assertNull(mc.get(KEY_A)); assertNull(mc.get(KEY_B)); assertNull(mc.get(KEY_C)); } @After public void tearDown() throws Exception { mc.delete(KEY_A); mc.delete(KEY_B); mc.delete(KEY_C); mc.close(); } @Test public void testSetGet() throws Exception { mc.set(KEY_A, "A"); assertEquals("A", mc.get(KEY_A)); } @Test public void testSetGetNewLineChars() throws Exception { mc.set(KEY_A, "A\r\nA"); assertEquals("A\r\nA", mc.get(KEY_A)); } @Test public void testSetGetObject() throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oo = new ObjectOutputStream(bout); oo.writeObject(new TestSerializable("CONTENT")); oo.flush(); byte[] byteData = bout.toByteArray(); mc.writeln("set " + KEY_A + " 0 0 " + byteData.length); mc.flush(); mc.write(byteData); mc.write("\r\n".getBytes(ENCODING)); mc.flush(); assertEquals("STORED", mc.readln()); byte[] bytesBack = mc.getBytes(KEY_A); assertEquals(byteData.length, bytesBack.length); ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(bytesBack)); TestSerializable ts = (TestSerializable) oin.readObject(); assertEquals("CONTENT", ts.getContent()); } @Test public void testSetGetFlags() throws Exception { mc.writeln("set " + KEY_A + " 1234 0 1"); mc.writeln("A"); mc.flush(); assertEquals("STORED", mc.readln()); mc.writeln("get " + KEY_A); mc.flush(); assertEquals("VALUE " + KEY_A + " 1234 1", mc.readln()); assertEquals("A", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testSecondSet() throws Exception { mc.set(KEY_A, "A"); assertEquals("A", mc.get(KEY_A)); mc.set(KEY_A, "B"); assertEquals("B", mc.get(KEY_A)); } @Test public void testGetMultipleKeys() throws Exception { mc.set(KEY_A, "A"); mc.set(KEY_B, "B"); mc.writeln("get " + KEY_A + " " + KEY_B); mc.flush(); assertEquals("VALUE " + KEY_A + " 0 1", mc.readln()); assertEquals("A", mc.readln()); assertEquals("VALUE " + KEY_B + " 0 1", mc.readln()); assertEquals("B", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testAdd() throws Exception { String data = "testAdd"; mc.writeln("add " + KEY_A + " 0 0 " + data.getBytes(ENCODING).length); mc.writeln(data); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals(data, mc.get(KEY_A)); // second add mc.writeln("add " + KEY_A + " 0 0 " + data.getBytes(ENCODING).length); mc.writeln(data); mc.flush(); assertEquals("NOT_STORED", mc.readln()); } @Test public void testReplace() throws Exception { mc.set(KEY_A, "testAdd"); assertEquals("testAdd", mc.get(KEY_A)); // replace mc.writeln("replace " + KEY_A + " 0 0 " + "replacement".getBytes(ENCODING).length); mc.writeln("replacement"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("replacement", mc.get(KEY_A)); } @Test public void testReplaceNonExistent() throws Exception { mc.writeln("replace " + KEY_A + " 0 0 " + "replacement".getBytes(ENCODING).length); mc.writeln("replacement"); mc.flush(); assertEquals("NOT_STORED", mc.readln()); } @Test public void testAppend() throws Exception { mc.set(KEY_A, "Hello"); assertEquals("Hello", mc.get(KEY_A)); mc.writeln("append " + KEY_A + " 0 0 " + ", World!".getBytes(ENCODING).length); mc.writeln(", World!"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("Hello, World!", mc.get(KEY_A)); } @Test public void testAppendNonExistent() throws Exception { mc.writeln("append " + KEY_A + " 0 0 " + ", World!".getBytes(ENCODING).length); mc.writeln(", World!"); mc.flush(); assertEquals("NOT_STORED", mc.readln()); } @Test public void testPrepend() throws Exception { mc.set(KEY_A, "World!"); assertEquals("World!", mc.get(KEY_A)); mc.writeln("prepend " + KEY_A + " 0 0 " + "Hello, ".getBytes(ENCODING).length); mc.writeln("Hello, "); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("Hello, World!", mc.get(KEY_A)); } @Test public void testPrependNonExistent() throws Exception { mc.writeln("prepend " + KEY_A + " 0 0 " + "Hello, ".getBytes(ENCODING).length); mc.writeln("Hello, "); mc.flush(); assertEquals("NOT_STORED", mc.readln()); } @Test public void testCas() throws Exception { mc.set(KEY_A, "A"); mc.writeln("gets " + KEY_A); mc.flush(); String[] valueline = mc.readln().split(" "); assertEquals("VALUE", valueline[0]); assertEquals(KEY_A, valueline[1]); assertEquals("0", valueline[2]); // flags assertEquals("1", valueline[3]); // number of bytes in str "A" assertEquals("A", mc.readln()); String casId = valueline[4]; assertEquals("END", mc.readln()); mc.writeln("cas " + KEY_A + " 0 0 1 " + casId); mc.writeln("B"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("B", mc.get(KEY_A)); mc.writeln("gets " + KEY_A); mc.flush(); valueline = mc.readln().split(" "); assertFalse(casId.equals(valueline[4])); assertEquals("B", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testCasExists() throws Exception { mc.set(KEY_A, "A"); mc.writeln("gets " + KEY_A); mc.flush(); String[] valueline = mc.readln().split(" "); assertEquals("VALUE", valueline[0]); assertEquals(KEY_A, valueline[1]); assertEquals("0", valueline[2]); // flags assertEquals("1", valueline[3]); // number of bytes in str "A" assertEquals("A", mc.readln()); String casId = valueline[4]; assertEquals("END", mc.readln()); mc.writeln("cas " + KEY_A + " 0 0 1 1" + casId); // note appended 1 before casId mc.writeln("B"); mc.flush(); assertEquals("EXISTS", mc.readln()); assertEquals("A", mc.get(KEY_A)); } @Test public void testGetNotFound() throws Exception { mc.writeln("get " + KEY_A); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testCasNotFound() throws Exception { mc.writeln("cas " + KEY_A + " 0 0 1 1"); mc.writeln("B"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); } @Test public void testExpTime() throws Exception { mc.writeln("set " + KEY_A + " 0 2 1"); mc.writeln("A"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("A", mc.get(KEY_A)); sleepForSecs(2.5); assertNull(mc.get(KEY_A)); } /** * NOTE: This is randomly failing test on various platforms. * * @throws Exception */ @Test public void testExpTimeMaxSeconds() throws Exception { // set exp.time to max number treated as seconds // 2592000 = 60*60*24*30 mc.writeln("set " + KEY_A + " 0 2592000 1"); mc.writeln("A"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("A", mc.get(KEY_A)); sleepForSecs(2); assertEquals("A", mc.get(KEY_A)); } @Test public void testExpTimeAbsolutePast() throws Exception { // set exp.time to min number treated as unix time // 2592001 = 60*60*24*30 + 1 // corresponding to Sat, 31 Jan 1970 00:00:01 GMT mc.writeln("set " + KEY_A + " 0 2592001 1"); mc.writeln("A"); mc.flush(); assertEquals("STORED", mc.readln()); // should expire immediately (the next millisecond) // the sleep here is only to make sure that System.currentTimeMillis() // increases before next get Thread.sleep(5); assertNull(mc.get(KEY_A)); } @Test public void testExpTimeAbsoluteFuture() throws Exception { long now = mc.getServerTime(); log.tracef("server time: " + now); mc.writeln("set " + KEY_A + " 0 " + (now + 2) + " 1"); mc.writeln("A"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("A", mc.get(KEY_A)); sleepForSecs(2); assertNull(mc.get(KEY_A)); } private String key250() { String key250 = ""; for (int i = 0; i < 250; i++) { key250 += "a"; } return key250; } @Test public void testKeyLonger250() throws Exception { String key250 = key250(); mc.delete(key250); String key251 = key250 + "a"; // byte length is the same, because we're using "UTF-8 safe" char 'a' assertEquals(key250.length(), key250.getBytes(ENCODING).length); assertEquals(key251.length(), key251.getBytes(ENCODING).length); mc.set(key250, "A"); assertEquals("A", mc.get(key250)); mc.writeln("set " + key251 + " 0 0 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Get() throws Exception { mc.writeln("get " + key250() + "a"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Gets() throws Exception { mc.writeln("gets " + key250() + "a"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Multiget() throws Exception { String key250 = key250(); String key251 = key250 + "a"; // byte length is the same, because we're using "UTF-8 safe" char 'a' assertEquals(key250.length(), key250.getBytes(ENCODING).length); assertEquals(key251.length(), key251.getBytes(ENCODING).length); mc.set(key250, "A"); assertEquals("A", mc.get(key250)); mc.writeln("get " + key250 + " " + key251); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); assertEquals("DELETED", mc.delete(key250)); } @Test public void testKeyLonger250Add() throws Exception { String key250 = key250(); mc.delete(key250); String key251 = key250 + "a"; // byte length is the same, because we're using "UTF-8 safe" char 'a' assertEquals(key250.length(), key250.getBytes(ENCODING).length); assertEquals(key251.length(), key251.getBytes(ENCODING).length); mc.writeln("add " + key250 + " 0 0 1"); mc.writeln("A"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("A", mc.get(key250)); mc.writeln("add " + key251 + " 0 0 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Replace() throws Exception { mc.writeln("replace " + key250() + "a 0 0 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Append() throws Exception { mc.writeln("append " + key250() + "a 0 0 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Prepend() throws Exception { mc.writeln("prepend " + key250() + "a 0 0 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Cas() throws Exception { mc.writeln("prepend " + key250() + "a 0 0 1 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Incr() throws Exception { mc.writeln("incr " + key250() + "a 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Decr() throws Exception { mc.writeln("decr " + key250() + "a 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testKeyLonger250Delete() throws Exception { mc.writeln("delete " + key250() + "a"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testDelete() throws Exception { mc.set(KEY_A, "A"); assertEquals("A", mc.get(KEY_A)); assertEquals("DELETED", mc.delete(KEY_A)); assertNull(mc.get(KEY_A)); } @Test public void testDeleteNonExistent() throws Exception { assertEquals("NOT_FOUND", mc.delete(KEY_A)); } @Test public void testIncr() throws Exception { mc.set(KEY_A, "0"); mc.writeln("incr " + KEY_A + " 1"); mc.flush(); assertEquals("1", mc.readln()); } @Test public void testDecr() throws Exception { mc.set(KEY_A, "1"); mc.writeln("decr " + KEY_A + " 1"); mc.flush(); assertEquals("0", mc.readln()); } @Test public void testIncrNotFound() throws Exception { mc.writeln("incr " + KEY_A + " 1"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); } @Test public void testDecrNotFound() throws Exception { mc.writeln("decr " + KEY_A + " 1"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); } @Test public void testIncr64BitMax() throws Exception { mc.set(KEY_A, "18446744073709551614"); mc.writeln("incr " + KEY_A + " 1"); mc.flush(); assertEquals("18446744073709551615", mc.readln()); mc.writeln("incr " + KEY_A + " 1"); mc.flush(); assertEquals("0", mc.readln()); } @Test public void testDecrZero() throws Exception { mc.set(KEY_A, "0"); mc.writeln("decr " + KEY_A + " 1"); mc.flush(); assertEquals("0", mc.readln()); } @Test public void testIncrBigIncrement() throws Exception { mc.set(KEY_A, "0"); mc.writeln("incr " + KEY_A + " 18446744073709551615"); mc.flush(); assertEquals("18446744073709551615", mc.readln()); } @Test public void testIncrBigDecrement() throws Exception { mc.set(KEY_A, "18446744073709551615"); mc.writeln("decr " + KEY_A + " 18446744073709551615"); mc.flush(); assertEquals("0", mc.readln()); } @Test public void testUnsupportedStats() throws Exception { Map<String, String> stats = mc.getStats(); assertEquals(stats.get("pid"), "0"); assertEquals(stats.get("pointer_size"), "0"); assertEquals(stats.get("rusage_user"), "0"); assertEquals(stats.get("rusage_system"), "0"); assertEquals(stats.get("bytes"), "0"); assertEquals(stats.get("curr_connections"), "0"); assertEquals(stats.get("total_connections"), "0"); assertEquals(stats.get("connection_structures"), "0"); assertEquals(stats.get("auth_cmds"), "0"); assertEquals(stats.get("auth_errors"), "0"); assertEquals(stats.get("limit_maxbytes"), "0"); assertEquals(stats.get("conn_yields"), "0"); assertEquals(stats.get("threads"), "0"); } @Test public void testStatsBytes() throws Exception { Map<String, String> stats = mc.getStats(); int bytesRead = new Integer(stats.get("bytes_read")); int bytesWritten = new Integer(stats.get("bytes_written")); mc.set("testKey", "testValue"); mc.get("testKey"); mc.delete("testKey"); stats = mc.getStats(); assertTrue("Bytes read didnt increase.", bytesRead < Integer.parseInt(stats.get("bytes_read"))); assertTrue("Bytes written didnt increase.", bytesWritten < Integer.parseInt(stats.get("bytes_written"))); } @Test public void testStatsTime() throws Exception { Map<String, String> stats = mc.getStats(); int uptime = new Integer(stats.get("uptime")); int time = new Integer(stats.get("time")); sleepForSecs(1); stats = mc.getStats(); assertTrue(uptime < new Integer(stats.get("uptime"))); assertTrue(time < new Integer(stats.get("time"))); } @Test public void testStatsVersion() throws Exception { Map<String, String> stats = mc.getStats(); String version = stats.get("version"); assertNotNull(version); assertTrue(version.startsWith(Version.getMajorMinor())); } @Test public void testStatsGetSetItemCount() throws Exception { Map<String, String> stats = mc.getStats(); int cmd_set = new Integer(stats.get("cmd_set")); int cmd_get = new Integer(stats.get("cmd_get")); int get_hits = new Integer(stats.get("get_hits")); int get_misses = new Integer(stats.get("get_misses")); int curr_items = new Integer(stats.get("curr_items")); int total_items = new Integer(stats.get("total_items")); mc.set(KEY_A, "A"); assertEquals("A", mc.get(KEY_A)); assertNull(mc.get(KEY_B)); stats = mc.getStats(); int cmd_set_new = new Integer(stats.get("cmd_set")); int cmd_get_new = new Integer(stats.get("cmd_get")); int get_hits_new = new Integer(stats.get("get_hits")); int get_misses_new = new Integer(stats.get("get_misses")); int curr_items_new = new Integer(stats.get("curr_items")); int total_items_new = new Integer(stats.get("total_items")); assertEquals(cmd_get + 2, cmd_get_new); assertEquals(cmd_set + 1, cmd_set_new); assertEquals(get_hits + 1, get_hits_new); assertEquals(get_misses + 1, get_misses_new); assertEquals(curr_items + 1, curr_items_new); assertEquals(total_items + 1, total_items_new); } @Test public void testStatsDelete() throws Exception { Map<String, String> stats = mc.getStats(); int delete_misses = new Integer(stats.get("delete_misses")); int delete_hits = new Integer(stats.get("delete_hits")); mc.set(KEY_A, "A"); assertEquals("DELETED", mc.delete(KEY_A)); assertEquals("NOT_FOUND", mc.delete(KEY_B)); stats = mc.getStats(); int delete_misses_new = new Integer(stats.get("delete_misses")); int delete_hits_new = new Integer(stats.get("delete_hits")); assertEquals(delete_misses + 1, delete_misses_new); assertEquals(delete_hits + 1, delete_hits_new); } @Test public void testStatsIncrDecr() throws Exception { Map<String, String> stats = mc.getStats(); int incr_misses = new Integer(stats.get("incr_misses")); int incr_hits = new Integer(stats.get("incr_hits")); int decr_misses = new Integer(stats.get("decr_misses")); int decr_hits = new Integer(stats.get("decr_hits")); mc.set(KEY_A, "0"); mc.writeln("incr " + KEY_A + " 1"); mc.flush(); assertEquals("1", mc.readln()); mc.writeln("decr " + KEY_A + " 1"); mc.flush(); assertEquals("0", mc.readln()); mc.writeln("incr " + KEY_B + " 1"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); mc.writeln("decr " + KEY_B + " 1"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); stats = mc.getStats(); int incr_misses_new = new Integer(stats.get("incr_misses")); int incr_hits_new = new Integer(stats.get("incr_hits")); int decr_misses_new = new Integer(stats.get("decr_misses")); int decr_hits_new = new Integer(stats.get("decr_hits")); assertEquals(incr_misses + 1, incr_misses_new); assertEquals(incr_hits + 1, incr_hits_new); assertEquals(decr_misses + 1, decr_misses_new); assertEquals(decr_hits + 1, decr_hits_new); } @Test public void testStatsCas() throws Exception { Map<String, String> stats = mc.getStats(); int cas_misses = new Integer(stats.get("cas_misses")); int cas_hits = new Integer(stats.get("cas_hits")); // cas hit mc.set(KEY_A, "A"); mc.writeln("gets " + KEY_A); mc.flush(); String[] valueline = mc.readln().split(" "); assertEquals("VALUE", valueline[0]); assertEquals(KEY_A, valueline[1]); assertEquals("0", valueline[2]); // flags assertEquals("1", valueline[3]); // number of bytes in str "A" assertEquals("A", mc.readln()); String casId = valueline[4]; assertEquals("END", mc.readln()); mc.writeln("cas " + KEY_A + " 0 0 1 " + casId); mc.writeln("B"); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("B", mc.get(KEY_A)); // cas miss mc.writeln("cas " + KEY_B + " 0 0 1 1"); mc.writeln("B"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); stats = mc.getStats(); int cas_misses_new = new Integer(stats.get("cas_misses")); int cas_hits_new = new Integer(stats.get("cas_hits")); assertEquals(cas_misses + 1, cas_misses_new); assertEquals(cas_hits + 1, cas_hits_new); int cas_badval = new Integer(stats.get("cas_badval")); // cas bad value mc.writeln("cas " + KEY_A + " 0 0 1 1" + casId); // note appended 1 before casId mc.writeln("C"); mc.flush(); assertEquals("EXISTS", mc.readln()); stats = mc.getStats(); int cas_badval_new = new Integer(stats.get("cas_badval")); assertEquals(cas_badval + 1, cas_badval_new); } @Test public void testBogusCommand() throws Exception { mc.writeln("boguscommand"); mc.flush(); assertStartsWith(mc.readln(), "ERROR"); } @Test public void testBogusCommandArgs() throws Exception { mc.writeln("boguscommand arg1 arg2 arg3"); mc.flush(); assertStartsWith(mc.readln(), "ERROR"); } @Test public void testBogusCommandPipeline() throws Exception { mc.writeln("boguscommand"); mc.writeln("delete " + KEY_A); mc.flush(); assertStartsWith(mc.readln(), "ERROR"); assertEquals("NOT_FOUND", mc.readln()); } @Test public void testCasParsing1() throws Exception { mc.writeln("cas bad blah 0 0 0"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testCasParsing2() throws Exception { mc.writeln("cas bad 0 blah 0 0"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testCasParsing3() throws Exception { mc.writeln("cas bad 0 0 blah 0"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testCasParsing4() throws Exception { mc.writeln("cas bad 0 0 0 blah"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } // missing cas unique value @Test public void testCasParsing6() throws Exception { mc.writeln("cas bad 0 0 6"); mc.flush(); assertStartsWith(mc.readln(), "SERVER_ERROR"); } @Test public void testCasUniqueIs64Bit() throws Exception { // casid should be 64 bit value, in our case signed // ie. should have range Long.MIN_VALUE .. Long.MAX_VALUE mc.writeln("cas a 0 0 1 " + Long.MAX_VALUE); mc.writeln("a"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); mc.writeln("cas a 0 0 1 " + Long.MIN_VALUE); mc.writeln("a"); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); } @Test public void testSetFlagsRange() throws Exception { mc.writeln("set a 0 0 1"); mc.writeln("a"); mc.flush(); assertEquals("STORED", mc.readln()); mc.writeln("set a 4294967295 0 1"); mc.writeln("a"); mc.flush(); assertEquals("STORED", mc.readln()); mc.writeln("set a -1 0 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); mc.writeln("set a 4294967296 0 1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testVerbosityUnsupported() throws Exception { mc.writeln("verbosity 0"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testQuit() throws Exception { mc.writeln("quit"); mc.flush(); assertEquals("", mc.readln()); } @Test public void testFlushAll() throws Exception { mc.set(KEY_A, "valA"); mc.set(KEY_B, "valB"); mc.set(KEY_C, "valC"); assertEquals("valA", mc.get(KEY_A)); assertEquals("valB", mc.get(KEY_B)); assertEquals("valC", mc.get(KEY_C)); mc.writeln("flush_all"); mc.flush(); assertEquals("OK", mc.readln()); assertNull(mc.get(KEY_A)); assertNull(mc.get(KEY_B)); assertNull(mc.get(KEY_C)); } @Test public void testFlushAllDelayed() throws Exception { mc.set(KEY_A, "valA"); mc.set(KEY_B, "valB"); mc.set(KEY_C, "valC"); assertEquals("valA", mc.get(KEY_A)); assertEquals("valB", mc.get(KEY_B)); assertEquals("valC", mc.get(KEY_C)); mc.writeln("flush_all 1"); mc.flush(); assertEquals("OK", mc.readln()); assertEquals("valA", mc.get(KEY_A)); assertEquals("valB", mc.get(KEY_B)); assertEquals("valC", mc.get(KEY_C)); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return mc.get(KEY_A) == null && mc.get(KEY_B) == null && mc.get(KEY_C) == null; } }, 20000, 40); } @Test public void testFlushAllDelayedUnixTime() throws Exception { mc.set(KEY_A, "valA"); mc.set(KEY_B, "valB"); mc.set(KEY_C, "valC"); assertEquals("valA", mc.get(KEY_A)); assertEquals("valB", mc.get(KEY_B)); assertEquals("valC", mc.get(KEY_C)); long t = mc.getServerTime(); assertTrue(t > 0); mc.writeln("flush_all " + (t + 2)); mc.flush(); assertEquals("OK", mc.readln()); assertEquals("valA", mc.get(KEY_A)); assertEquals("valB", mc.get(KEY_B)); assertEquals("valC", mc.get(KEY_C)); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return mc.get(KEY_A) == null && mc.get(KEY_B) == null && mc.get(KEY_C) == null; } }, 20000, 40); } @Test public void testPipeliningSet() throws Exception { mc.writeln("set " + KEY_A + " 0 0 1"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningAdd() throws Exception { mc.writeln("add " + KEY_A + " 0 0 1"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningReplace() throws Exception { mc.set(KEY_A, "b"); mc.writeln("replace " + KEY_A + " 0 0 1"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningAppend() throws Exception { mc.set(KEY_A, "a"); mc.writeln("append " + KEY_A + " 0 0 1"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningPrepend() throws Exception { mc.set(KEY_A, "a"); mc.writeln("prepend " + KEY_A + " 0 0 1"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("STORED", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningCas() throws Exception { mc.writeln("cas " + KEY_A + " 0 0 1 0"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningGet() throws Exception { mc.writeln("get " + KEY_A); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningGetMulti() throws Exception { mc.writeln("get " + KEY_A + " " + KEY_C); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningGets() throws Exception { mc.writeln("gets " + KEY_A); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningGetsMulti() throws Exception { mc.writeln("gets " + KEY_A + " " + KEY_C); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningDelete() throws Exception { mc.writeln("delete " + KEY_A); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("NOT_FOUND", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningIncr() throws Exception { mc.set(KEY_A, "1"); mc.writeln("incr " + KEY_A + " 1"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("2", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningDecr() throws Exception { mc.set(KEY_A, "2"); mc.writeln("decr " + KEY_A + " 1"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("1", mc.readln()); assertEquals("END", mc.readln()); } @Test(timeout = 5000) public void testPipeliningStats() throws Exception { mc.writeln("stats"); mc.writeln("get " + KEY_B); mc.flush(); String line = null; do { line = mc.readln(); } while (!line.equals("END")); assertEquals("END", mc.readln()); } @Test public void testPipeliningVersion() throws Exception { mc.writeln("version"); mc.writeln("get " + KEY_B); mc.flush(); assertNotNull(mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningVerbosity() throws Exception { mc.writeln("verbosity 0"); mc.writeln("get " + KEY_B); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); assertEquals("END", mc.readln()); } @Test public void testPipeliningFlushAll() throws Exception { mc.writeln("flush_all"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("OK", mc.readln()); assertEquals("END", mc.readln()); } @Test public void testPipeliningFlushAllDelayed() throws Exception { mc.writeln("flush_all 1"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("OK", mc.readln()); assertEquals("END", mc.readln()); mc.set(KEY_A, "thisWillBeFlushed"); assertEquals("thisWillBeFlushed", mc.get(KEY_A)); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return mc.get(KEY_A) == null; } }, 20000, 40); } @Test public void testStatsArgs() throws Exception { mc.writeln("stats args"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testNegativeItemSize() throws Exception { mc.writeln("set a 0 0 -1"); mc.flush(); assertStartsWith(mc.readln(), "CLIENT_ERROR"); } @Test public void testNoReplySet() throws Exception { mc.writeln("set " + KEY_A + " 0 0 1 noreply"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyAdd() throws Exception { mc.writeln("add " + KEY_A + " 0 0 1 noreply"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyReplace() throws Exception { mc.set(KEY_A, "b"); mc.writeln("replace " + KEY_A + " 0 0 1 noreply"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyAppend() throws Exception { mc.set(KEY_A, "a"); mc.writeln("append " + KEY_A + " 0 0 1 noreply"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyPrepend() throws Exception { mc.set(KEY_A, "a"); mc.writeln("prepend " + KEY_A + " 0 0 1 noreply"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyCas() throws Exception { mc.writeln("cas " + KEY_A + " 0 0 1 0 noreply"); mc.writeln("a"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyDelete() throws Exception { mc.writeln("delete " + KEY_A + " noreply"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyIncr() throws Exception { mc.set(KEY_A, "1"); mc.writeln("incr " + KEY_A + " 1 noreply"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyDecr() throws Exception { mc.set(KEY_A, "2"); mc.writeln("decr " + KEY_A + " 1 noreply"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyFlushAll() throws Exception { mc.writeln("flush_all noreply"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); } @Test public void testNoReplyFlushAllDelayed() throws Exception { mc.writeln("flush_all 1 noreply"); mc.writeln("get " + KEY_B); mc.flush(); assertEquals("END", mc.readln()); mc.set(KEY_A, "thisWillBeFlushed"); assertEquals("thisWillBeFlushed", mc.get(KEY_A)); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { return mc.get(KEY_A) == null; } }, 20000, 40); } private void assertStartsWith(String str, String prefix) { assertTrue("String \"" + str + "\" doesn't start with expected prefix \"" + prefix + "\"", str.startsWith(prefix)); } }