package org.infinispan.server.hotrod; import static org.infinispan.server.hotrod.OperationStatus.InvalidMagicOrMsgId; import static org.infinispan.server.hotrod.OperationStatus.KeyDoesNotExist; import static org.infinispan.server.hotrod.OperationStatus.NotExecutedWithPrevious; import static org.infinispan.server.hotrod.OperationStatus.OperationNotExecuted; import static org.infinispan.server.hotrod.OperationStatus.ParseError; import static org.infinispan.server.hotrod.OperationStatus.Success; import static org.infinispan.server.hotrod.OperationStatus.SuccessWithPrevious; import static org.infinispan.server.hotrod.OperationStatus.UnknownOperation; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertHotRodEquals; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertKeyDoesNotExist; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertStatus; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.assertSuccess; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.k; import static org.infinispan.server.hotrod.test.HotRodTestingUtil.v; import static org.infinispan.test.TestingUtil.generateRandomString; import static org.testng.Assert.assertEquals; import static org.testng.AssertJUnit.assertTrue; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.infinispan.server.hotrod.configuration.HotRodServerConfiguration; import org.infinispan.server.hotrod.test.TestBulkGetKeysResponse; import org.infinispan.server.hotrod.test.TestBulkGetResponse; import org.infinispan.server.hotrod.test.TestErrorResponse; import org.infinispan.server.hotrod.test.TestGetResponse; import org.infinispan.server.hotrod.test.TestGetWithVersionResponse; import org.infinispan.server.hotrod.test.TestQueryResponse; import org.infinispan.server.hotrod.test.TestResponse; import org.infinispan.server.hotrod.test.TestResponseWithPrevious; import org.infinispan.server.hotrod.test.TestSizeResponse; import org.testng.annotations.Test; /** * Hot Rod server functional test. * * @author Galder ZamarreƱo * @since 4.1 */ @Test(groups = "functional", testName = "server.hotrod.HotRodFunctionalTest") public class HotRodFunctionalTest extends HotRodSingleNodeTest { public void testUnknownCommand(Method m) { OperationStatus status = client().execute(0xA0, (byte) 0x77, cacheName, k(m), 0, 0, v(m), 0, (byte) 1, 0).status; assertEquals(status, UnknownOperation, "Status should have been 'UnknownOperation' but instead was: " + status); } public void testUnknownMagic(Method m) { client().assertPut(m); // Do a put to make sure decoder gets back to reading properly OperationStatus status = client().executeExpectBadMagic(0x66, (byte) 0x01, cacheName, k(m), 0, 0, v(m), 0).status; assertEquals(status, InvalidMagicOrMsgId, "Status should have been 'InvalidMagicOrMsgId' but instead was: " + status); } // todo: test other error conditions such as invalid version...etc public void testPutBasic(Method m) { client().assertPut(m); } public void testPutOnDefaultCache(Method m) { TestResponse resp = client().execute(0xA0, (byte) 0x01, "", k(m), 0, 0, v(m), 0, (byte) 1, 0); assertStatus(resp, Success); assertHotRodEquals(cacheManager, k(m), v(m)); } public void testPutOnUndefinedCache(Method m) { TestErrorResponse resp = ((TestErrorResponse) client().execute(0xA0, (byte) 0x01, "boomooo", k(m), 0, 0, v(m), 0, (byte) 1, 0)); assertTrue(resp.msg.contains("CacheNotFoundException")); assertEquals(resp.status, ParseError, "Status should have been 'ParseError' but instead was: " + resp.status); client().assertPut(m); } public void testPutOnTopologyCache(Method m) { TestErrorResponse resp = ((TestErrorResponse) client() .execute(0xA0, (byte) 0x01, HotRodServerConfiguration.TOPOLOGY_CACHE_NAME_PREFIX, k(m), 0, 0, v(m), 0, (byte) 1, 0)); assertTrue(resp.msg.contains("CacheNotFoundException")); assertEquals(resp.status, ParseError, "Status should have been 'ParseError' but instead was: " + resp.status); client().assertPut(m); } public void testPutWithLifespan(Method m) throws InterruptedException { client().assertPut(m, 1, 0); Thread.sleep(1100); assertKeyDoesNotExist(client().assertGet(m)); } public void testPutWithMaxIdle(Method m) throws InterruptedException { client().assertPut(m, 0, 1); Thread.sleep(1100); assertKeyDoesNotExist(client().assertGet(m)); } public void testPutWithPreviousValue(Method m) { TestResponseWithPrevious resp = ((TestResponseWithPrevious) client().put(k(m), 0, 0, v(m), 1)); assertSuccessPrevious(resp, null); resp = (TestResponseWithPrevious) client().put(k(m), 0, 0, v(m, "v2-"), 1); assertSuccessPrevious(resp, v(m)); } public void testGetBasic(Method m) { client().assertPut(m); assertSuccess(client().assertGet(m), v(m)); } public void testGetDoesNotExist(Method m) { assertKeyDoesNotExist(client().assertGet(m)); } public void testPutIfAbsentNotExist(Method m) { TestResponse resp = client().putIfAbsent(k(m), 0, 0, v(m)); assertStatus(resp, Success); } public void testPutIfAbsentExist(Method m) { client().assertPut(m); TestResponse resp = client().putIfAbsent(k(m), 0, 0, v(m, "v2-")); assertStatus(resp, OperationNotExecuted); } public void testPutIfAbsentWithLifespan(Method m) throws InterruptedException { TestResponse resp = client().putIfAbsent(k(m), 1, 0, v(m)); assertStatus(resp, Success); Thread.sleep(1100); assertKeyDoesNotExist(client().assertGet(m)); } public void testPutIfAbsentWithMaxIdle(Method m) throws InterruptedException { TestResponse resp = client().putIfAbsent(k(m), 0, 1, v(m)); assertStatus(resp, Success); Thread.sleep(1100); assertKeyDoesNotExist(client().assertGet(m)); } public void testPutIfAbsentWithPreviousValue(Method m) { TestResponse resp1 = client().putIfAbsent(k(m), 0, 0, v(m), 0); assertStatus(resp1, Success); TestResponseWithPrevious resp2 = (TestResponseWithPrevious) client().putIfAbsent(k(m), 0, 0, v(m, "v2-"), 1); assertNotExecutedPrevious(resp2, v(m)); } public void testReplaceBasic(Method m) { client().assertPut(m); TestResponse resp = client().replace(k(m), 0, 0, v(m, "v1-")); assertStatus(resp, Success); assertSuccess(client().assertGet(m), v(m, "v1-")); } public void testNotReplaceIfNotPresent(Method m) { TestResponse resp = client().replace(k(m), 0, 0, v(m)); assertStatus(resp, OperationNotExecuted); } public void testReplaceWithLifespan(Method m) throws InterruptedException { client().assertPut(m); TestResponse resp = client().replace(k(m), 1, 0, v(m, "v1-")); assertStatus(resp, Success); Thread.sleep(1100); assertKeyDoesNotExist(client().assertGet(m)); } public void testReplaceWithMaxIdle(Method m) throws InterruptedException { client().assertPut(m); TestResponse resp = client().replace(k(m), 0, 1, v(m, "v1-")); assertStatus(resp, Success); Thread.sleep(1100); assertKeyDoesNotExist(client().assertGet(m)); } public void testReplaceWithPreviousValue(Method m) { TestResponse resp = client().replace(k(m), 0, 0, v(m), 0); assertStatus(resp, OperationNotExecuted); TestResponseWithPrevious resp2 = (TestResponseWithPrevious) client().put(k(m), 0, 0, v(m, "v2-"), 1); assertSuccessPrevious(resp2, null); TestResponseWithPrevious resp3 = (TestResponseWithPrevious) client().replace(k(m), 0, 0, v(m, "v3-"), 1); assertSuccessPrevious(resp3, v(m, "v2-")); } public void testGetWithVersionBasic(Method m) { client().assertPut(m); assertSuccess(client().getWithVersion(k(m), 0), v(m), 0); } public void testGetWithVersionDoesNotExist(Method m) { TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertKeyDoesNotExist(resp); assertTrue(resp.dataVersion == 0); } public void testGetWithMetadata(Method m) { client().assertPut(m); assertSuccess(client().assertGet(m), v(m)); assertSuccess(client().getWithMetadata(k(m), 0), v(m), -1, -1); client().remove(k(m)); client().assertPut(m, 10, 5); assertSuccess(client().getWithMetadata(k(m), 0), v(m), 10, 5); } public void testReplaceIfUnmodifiedBasic(Method m) { client().assertPut(m); TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertSuccess(resp, v(m), 0); TestResponse resp2 = client().replaceIfUnmodified(k(m), 0, 0, v(m, "v1-"), resp.dataVersion); assertStatus(resp2, Success); } public void testReplaceIfUnmodifiedNotFound(Method m) { client().assertPut(m); TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertSuccess(resp, v(m), 0); TestResponse resp2 = client().replaceIfUnmodified(k(m, "k1-"), 0, 0, v(m, "v1-"), resp.dataVersion); assertStatus(resp2, KeyDoesNotExist); } public void testReplaceIfUnmodifiedNotExecuted(Method m) { client().assertPut(m); TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertSuccess(resp, v(m), 0); TestResponse resp2 = client().replaceIfUnmodified(k(m), 0, 0, v(m, "v1-"), resp.dataVersion); assertStatus(resp2, Success); TestGetWithVersionResponse resp3 = client().getWithVersion(k(m), 0); assertSuccess(resp3, v(m, "v1-"), 0); assertTrue(resp.dataVersion != resp3.dataVersion); TestResponse resp4 = client().replaceIfUnmodified(k(m), 0, 0, v(m, "v2-"), resp.dataVersion); assertStatus(resp4, OperationNotExecuted); TestResponse resp5 = client().replaceIfUnmodified(k(m), 0, 0, v(m, "v2-"), resp3.dataVersion); assertStatus(resp5, Success); } public void testReplaceIfUnmodifiedWithPreviousValue(Method m) { TestResponse resp = client().replaceIfUnmodified(k(m), 0, 0, v(m), 999, 0); assertStatus(resp, KeyDoesNotExist); client().assertPut(m); TestGetWithVersionResponse getResp = client().getWithVersion(k(m), 0); assertSuccess(getResp, v(m), 0); TestResponseWithPrevious resp2 = (TestResponseWithPrevious) client().replaceIfUnmodified(k(m), 0, 0, v(m, "v2-"), 888, 1); assertNotExecutedPrevious(resp2, v(m)); TestResponseWithPrevious resp3 = (TestResponseWithPrevious) client().replaceIfUnmodified(k(m), 0, 0, v(m, "v3-"), getResp.dataVersion, 1); assertSuccessPrevious(resp3, v(m)); } public void testReplaceIfUnmodifiedWithExpiry(Method m) throws InterruptedException { client().assertPut(m); TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertSuccess(resp, v(m), 0); assertTrue(resp.dataVersion != 0); int lifespanSecs = 2; long lifespan = TimeUnit.SECONDS.toMillis(lifespanSecs); long startTime = System.currentTimeMillis(); TestResponse resp2 = client().replaceIfUnmodified(k(m), lifespanSecs, 0, v(m, "v1-"), resp.dataVersion); assertStatus(resp2, Success); while (System.currentTimeMillis() < startTime + lifespan) { TestGetResponse getResponse = client().assertGet(m); // The entry could have expired before our request got to the server // Scala doesn't support break, so we need to test the current time twice if (System.currentTimeMillis() < startTime + lifespan) { assertSuccess(getResponse, v(m, "v1-")); Thread.sleep(100); } } waitNotFound(startTime, lifespan, m); assertKeyDoesNotExist(client().assertGet(m)); } private void waitNotFound(long startTime, long lifespan, Method m) throws InterruptedException { while (System.currentTimeMillis() < startTime + lifespan + 20000) { if (Success != client().assertGet(m).getStatus()) break; Thread.sleep(50); } } public void testRemoveBasic(Method m) { client().assertPut(m); TestResponse resp = client().remove(k(m)); assertStatus(resp, Success); assertKeyDoesNotExist(client().assertGet(m)); } public void testRemoveDoesNotExist(Method m) { assertStatus(client().remove(k(m)), KeyDoesNotExist); } public void testRemoveWithPreviousValue(Method m) { TestResponse resp = client().remove(k(m), 0); assertStatus(resp, KeyDoesNotExist); client().assertPut(m); TestResponseWithPrevious resp2 = (TestResponseWithPrevious) client().remove(k(m), 1); assertSuccessPrevious(resp2, v(m)); } public void testRemoveIfUnmodifiedBasic(Method m) { client().assertPut(m); TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertSuccess(resp, v(m), 0); assertTrue(resp.dataVersion != 0); TestResponse resp2 = client().removeIfUnmodified(k(m), 0, 0, v(m, "v1-"), resp.dataVersion); assertStatus(resp2, Success); assertKeyDoesNotExist(client().assertGet(m)); } public void testRemoveIfUnmodifiedNotFound(Method m) { client().assertPut(m); TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertSuccess(resp, v(m), 0); TestResponse resp2 = client().removeIfUnmodified(k(m, "k1-"), 0, 0, v(m, "v1-"), resp.dataVersion); assertStatus(resp2, KeyDoesNotExist); assertSuccess(client().assertGet(m), v(m)); } public void testRemoveIfUnmodifiedNotExecuted(Method m) { client().assertPut(m); TestGetWithVersionResponse resp = client().getWithVersion(k(m), 0); assertSuccess(resp, v(m), 0); TestResponse resp2 = client().replaceIfUnmodified(k(m), 0, 0, v(m, "v1-"), resp.dataVersion); assertStatus(resp2, Success); TestGetWithVersionResponse resp3 = client().getWithVersion(k(m), 0); assertSuccess(resp3, v(m, "v1-"), 0); assertTrue(resp.dataVersion != resp3.dataVersion); TestResponse resp4 = client().removeIfUnmodified(k(m), 0, 0, v(m, "v2-"), resp.dataVersion); assertStatus(resp4, OperationNotExecuted); TestResponse resp5 = client().removeIfUnmodified(k(m), 0, 0, v(m, "v2-"), resp3.dataVersion); assertStatus(resp5, Success); } public void testRemoveIfUmodifiedWithPreviousValue(Method m) { TestResponse resp = client().removeIfUnmodified(k(m), 999, 0); assertStatus(resp, KeyDoesNotExist); client().assertPut(m); TestGetWithVersionResponse getResp = client().getWithVersion(k(m), 0); assertSuccess(getResp, v(m), 0); TestResponseWithPrevious resp2 = (TestResponseWithPrevious) client().removeIfUnmodified(k(m), 888, 1); assertNotExecutedPrevious(resp2, v(m)); TestResponseWithPrevious resp3 = (TestResponseWithPrevious) client().removeIfUnmodified(k(m), getResp.dataVersion, 1); assertSuccessPrevious(resp3, v(m)); } public void testContainsKeyBasic(Method m) { client().assertPut(m); assertStatus(client().containsKey(k(m), 0), Success); } public void testContainsKeyDoesNotExist(Method m) { assertStatus(client().containsKey(k(m), 0), KeyDoesNotExist); } public void testClear(Method m) { for (int i = 1; i <= 5; i++) { byte[] key = k(m, "k" + i + "-"); byte[] value = v(m, "v" + i + "-"); assertStatus(client().put(key, 0, 0, value), Success); assertStatus(client().containsKey(key, 0), Success); } assertStatus(client().clear(), Success); for (int i = 1; i <= 5; i++) { byte[] key = k(m, "k" + i + "-"); assertStatus(client().containsKey(key, 0), KeyDoesNotExist); } } public void testStatsDisabled(Method m) { Map<String, String> s = client().stats(); assertEquals(s.get("timeSinceStart"), "-1"); assertEquals(s.get("currentNumberOfEntries"), "-1"); assertEquals(s.get("totalNumberOfEntries"), "-1"); assertEquals(s.get("stores"), "-1"); assertEquals(s.get("retrievals"), "-1"); assertEquals(s.get("hits"), "-1"); assertEquals(s.get("misses"), "-1"); assertEquals(s.get("removeHits"), "-1"); assertEquals(s.get("removeMisses"), "-1"); } public void testPing(Method m) { assertStatus(client().ping(), Success); } public void testPingWithTopologyAwareClient(Method m) { TestResponse resp = client().ping(); assertStatus(resp, Success); assertEquals(resp.topologyResponse, null); resp = client().ping((byte) 1, 0); assertStatus(resp, Success); assertEquals(resp.topologyResponse, null); resp = client().ping((byte) 2, 0); assertStatus(resp, Success); assertEquals(resp.topologyResponse, null); resp = client().ping((byte) 3, 0); assertStatus(resp, Success); assertEquals(resp.topologyResponse, null); } public void testBulkGet(Method m) { int size = 100; for (int i = 0; i < size; i++) { TestResponse resp = client().put(k(m, i + "k-"), 0, 0, v(m, i + "v-")); assertStatus(resp, Success); } TestBulkGetResponse resp = client().bulkGet(); assertStatus(resp, Success); Map<byte[], byte[]> bulkData = resp.bulkData; assertEquals(size, bulkData.size()); for (int i = 0; i < size; i++) { byte[] key = k(m, i + "k-"); List<Map.Entry<byte[], byte[]>> filtered = bulkData.entrySet().stream() .filter(entry -> Arrays.equals(entry.getKey(), key)) .collect(Collectors.toList()); assertEquals(1, filtered.size()); } size = 50; resp = client().bulkGet(size); assertStatus(resp, Success); bulkData = resp.bulkData; assertEquals(size, bulkData.size()); for (int i = 0; i < size; i++) { byte[] key = k(m, i + "k-"); List<Map.Entry<byte[], byte[]>> filtered = bulkData.entrySet().stream() .filter(entry -> Arrays.equals(entry.getKey(), key)) .collect(Collectors.toList()); if (!filtered.isEmpty()) { assertTrue(java.util.Arrays.equals(filtered.get(0).getValue(), v(m, i + "v-"))); } } } public void testBulkGetKeys(Method m) { int size = 100; for (int i = 0; i < size; i++) { TestResponse resp = client().put(k(m, i + "k-"), 0, 0, v(m, i + "v-")); assertStatus(resp, Success); } TestBulkGetKeysResponse resp = client().bulkGetKeys(); assertStatus(resp, Success); Set<byte[]> bulkData = resp.bulkData; assertEquals(size, bulkData.size()); for (int i = 0; i < size; i++) { int finalI = i; List<byte[]> filtered = bulkData.stream().filter(bytes -> Arrays.equals(bytes, k(m, finalI + "k-"))) .collect(Collectors.toList()); assertEquals(1, filtered.size()); } resp = client().bulkGetKeys(1); assertStatus(resp, Success); bulkData = resp.bulkData; assertEquals(size, bulkData.size()); for (int i = 0; i < size; i++) { int finalI = i; List<byte[]> filtered = bulkData.stream().filter(bytes -> java.util.Arrays.equals(bytes, k(m, finalI + "k-"))) .collect(Collectors.toList()); assertEquals(1, filtered.size()); } resp = client().bulkGetKeys(2); assertStatus(resp, Success); bulkData = resp.bulkData; assertEquals(size, bulkData.size()); for (int i = 0; i < size; i++) { int finalI = i; List<byte[]> filtered = bulkData.stream().filter(bytes -> Arrays.equals(bytes, k(m, finalI + "k-"))) .collect(Collectors.toList()); assertEquals(1, filtered.size()); } } public void testPutBigSizeKey(Method m) { // Not really necessary, SingleByteFrameDecoderChannelInitializer forces the server to retry even for small keys byte[] key = generateRandomString(1024).getBytes(); assertStatus(client().put(key, 0, 0, v(m)), Success); } public void testPutBigSizeValue(Method m) { // Not really necessary, SingleByteFrameDecoderChannelInitializer forces the server to retry even for small keys byte[] value = generateRandomString(1024).getBytes(); assertStatus(client().put(k(m), 0, 0, value), Success); } public void testQuery() { byte[] query = new byte[]{1, 2, 3, 4, 5}; TestQueryResponse resp = client().query(query); assertStatus(resp, Success); assertTrue(Arrays.equals(query, resp.result)); } public void testSize(Method m) { TestSizeResponse sizeStart = client().size(); assertStatus(sizeStart, Success); assertEquals(0, sizeStart.size); for (int i = 0; i < 20; i++) { client().assertPut(m, "k-" + i, "v-" + i); } TestSizeResponse sizeEnd = client().size(); assertStatus(sizeEnd, Success); assertEquals(20, sizeEnd.size); } protected boolean assertSuccessPrevious(TestResponseWithPrevious resp, byte[] expected) { if (expected == null) assertEquals(Optional.empty(), resp.previous); else assertTrue(java.util.Arrays.equals(expected, resp.previous.get())); return assertStatus(resp, SuccessWithPrevious); } protected boolean assertNotExecutedPrevious(TestResponseWithPrevious resp, byte[] expected) { if (expected == null) assertEquals(Optional.empty(), resp.previous); else assertTrue(java.util.Arrays.equals(expected, resp.previous.get())); return assertStatus(resp, NotExecutedWithPrevious); } }