package org.infinispan.client.hotrod; import static org.infinispan.client.hotrod.test.HotRodClientTestingUtil.loadScript; import static org.infinispan.client.hotrod.test.HotRodClientTestingUtil.withClientListener; import static org.infinispan.client.hotrod.test.HotRodClientTestingUtil.withScript; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertTrue; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import org.infinispan.client.hotrod.event.EventLogListener; import org.infinispan.client.hotrod.exceptions.HotRodClientException; import org.infinispan.client.hotrod.test.MultiHotRodServersTest; import org.infinispan.commons.marshall.jboss.GenericJBossMarshaller; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.scripting.ScriptingManager; import org.infinispan.scripting.utils.ScriptingUtils; import org.infinispan.test.TestingUtil; import org.infinispan.util.concurrent.IsolationLevel; import org.testng.AssertJUnit; import org.testng.annotations.AfterMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * ExecTest. * * @author Tristan Tarrant * @since 7.2 */ @Test(groups = "functional", testName = "client.hotrod.ExecTest") public class ExecTest extends MultiHotRodServersTest { private static final String SCRIPT_CACHE = "___script_cache"; static final String REPL_CACHE = "R"; static final String DIST_CACHE = "D"; static final int NUM_SERVERS = 2; static final int SIZE = 20; @Override protected void createCacheManagers() throws Throwable { createHotRodServers(NUM_SERVERS, new ConfigurationBuilder()); defineInAll(REPL_CACHE, CacheMode.REPL_SYNC); defineInAll(DIST_CACHE, CacheMode.DIST_SYNC); } @AfterMethod @Override protected void clearContent() throws Throwable { clients.get(0).getCache(REPL_CACHE).clear(); clients.get(0).getCache(DIST_CACHE).clear(); } private void defineInAll(String cacheName, CacheMode mode) { ConfigurationBuilder builder = getDefaultClusteredCacheConfig(mode, true); builder.dataContainer() .compatibility().enable() .marshaller(new GenericJBossMarshaller()) .locking().isolationLevel(IsolationLevel.READ_COMMITTED); defineInAll(cacheName, builder); } @Test(expectedExceptions = HotRodClientException.class, expectedExceptionsMessageRegExp = ".*Unknown task 'nonExistent\\.js'.*") public void testRemovingNonExistentScript() { clients.get(0).getCache().execute("nonExistent.js", new HashMap<>()); } @Test(dataProvider = "CacheNameProvider") public void testEmbeddedScriptRemoteExecution(String cacheName) throws IOException { withScript(manager(0), "/test.js", scriptName -> { populateCache(cacheName); assertEquals(SIZE, clients.get(0).getCache(cacheName).size()); Map<String, String> params = new HashMap<>(); params.put("parameter", "guinness"); Integer result = clients.get(0).getCache(cacheName).execute(scriptName, params); assertEquals(SIZE + 1, result.intValue()); assertEquals("guinness", clients.get(0).getCache(cacheName).get("parameter")); }); } @Test(dataProvider = "CacheNameProvider") public void testRemoteScriptRemoteExecution(String cacheName) throws IOException { withScript(manager(0), "/test.js", scriptName -> { populateCache(cacheName); assertEquals(SIZE, clients.get(0).getCache(cacheName).size()); Map<String, String> params = new HashMap<>(); params.put("parameter", "hoptimus prime"); Integer result = clients.get(0).getCache(cacheName).execute(scriptName, params); assertEquals(SIZE + 1, result.intValue()); assertEquals("hoptimus prime", clients.get(0).getCache(cacheName).get("parameter")); }); } @Test(enabled = false, dataProvider = "CacheModeProvider", description = "Enable when ISPN-6300 is fixed.") public void testScriptExecutionWithPassingParams(CacheMode cacheMode) throws IOException { String cacheName = "testScriptExecutionWithPassingParams_" + cacheMode.toString(); ConfigurationBuilder builder = getDefaultClusteredCacheConfig(cacheMode, true); builder.dataContainer().compatibility().enable().marshaller(new GenericJBossMarshaller()); defineInAll(cacheName, builder); try (InputStream is = this.getClass().getResourceAsStream("/distExec.js")) { String script = TestingUtil.loadFileAsString(is); manager(0).getCache(SCRIPT_CACHE).put("testScriptExecutionWithPassingParams.js", script); } populateCache(cacheName); assertEquals(SIZE, clients.get(0).getCache(cacheName).size()); Map<String, String> params = new HashMap<>(); params.put("a", "hoptimus prime"); List<String> result = clients.get(0).getCache(cacheName).execute("testScriptExecutionWithPassingParams.js", params); assertEquals(SIZE + 1, client(0).getCache(cacheName).size()); assertEquals("hoptimus prime", clients.get(0).getCache(cacheName).get("a")); assertEquals(2, result.size()); assertTrue(result.contains(manager(0).getAddress())); assertTrue(result.contains(manager(1).getAddress())); } private void populateCache(String cacheName) { for (int i = 0; i < SIZE; i++) clients.get(i % NUM_SERVERS).getCache(cacheName).put(String.format("Key %d", i), String.format("Value %d", i)); } @Test(enabled = false, dataProvider = "CacheModeProvider", description = "Disabling this test until the distributed scripts in DIST mode are fixed - ISPN-6173") public void testRemoteMapReduceWithStreams(CacheMode cacheMode) throws Exception { String cacheName = "testRemoteMapReduce_Streams_dist_" + cacheMode.toString(); ConfigurationBuilder builder = getDefaultClusteredCacheConfig(cacheMode, true); builder.dataContainer() .compatibility().enable().marshaller(new GenericJBossMarshaller()); defineInAll(cacheName, builder); waitForClusterToForm(cacheName); RemoteCache<String, String> cache = clients.get(0).getCache(cacheName); RemoteCache<String, String> scriptCache = clients.get(1).getCache(SCRIPT_CACHE); ScriptingUtils.loadData(cache, "/macbeth.txt"); ScriptingManager scriptingManager = manager(0).getGlobalComponentRegistry().getComponent(ScriptingManager.class); loadScript("/wordCountStream_dist.js", scriptingManager, "wordCountStream_dist.js"); ArrayList<Map<String, Long>> results = cache.execute("wordCountStream_dist.js", new HashMap<String, String>()); assertEquals(2, results.size()); assertEquals(3202, results.get(0).size()); assertEquals(3202, results.get(1).size()); assertTrue(results.get(0).get("macbeth").equals(287L)); assertTrue(results.get(1).get("macbeth").equals(287L)); } @Test(dataProvider = "CacheNameProvider") public void testExecPutConstantGet(String cacheName) throws IOException { withScript(manager(0), "/test-put-constant-get.js", scriptName -> { Map<String, String> params = new HashMap<>(); String result = clients.get(0).getCache(cacheName).execute(scriptName, params); assertEquals("hoptimus prime", result); assertEquals("hoptimus prime", clients.get(0).getCache(cacheName).get("a")); }); } @Test(dataProvider = "CacheNameProvider") public void testExecReturnNull(String cacheName) throws IOException { withScript(manager(0), "/test-null-return.js", scriptName -> { Object result = clients.get(0).getCache(cacheName).execute(scriptName, new HashMap<>()); assertEquals(null, result); }); } @Test(dataProvider = "CacheNameProvider") public void testLocalExecPutGet(String cacheName) { execPutGet(cacheName, "/test-put-get.js", ExecMode.LOCAL, "local-key", "local-value"); } @Test(dataProvider = "CacheNameProvider") public void testDistExecPutGet(String cacheName) { execPutGet(cacheName, "/test-put-get-dist.js", ExecMode.DIST, "dist-key", "dist-value"); } @Test(dataProvider = "CacheNameProvider") public void testLocalExecPutGetWithListener(String cacheName) { final EventLogListener<String> l = new EventLogListener<>(clients.get(0).getCache(cacheName)); withClientListener(l, remote -> withScript(manager(0), "/test-put-get.js", scriptName -> { Map<String, String> params = new HashMap<>(); params.put("k", "local-key-listen"); params.put("v", "local-value-listen"); String result = remote.execute(scriptName, params); l.expectOnlyCreatedEvent("local-key-listen"); assertEquals("local-value-listen", result); })); } private void execPutGet(String cacheName, String path, ExecMode mode, String key, String value) { withScript(manager(0), path, scriptName -> { Map<String, String> params = new HashMap<>(); params.put("k", key); params.put("v", value); params.put("cacheName", cacheName); Object results = clients.get(0).getCache(cacheName).execute(scriptName, params); mode.assertResult.accept(value, results); }); } @DataProvider(name = "CacheNameProvider") private static Object[][] provideCacheMode() { return new Object[][] {{REPL_CACHE}, {DIST_CACHE}}; } enum ExecMode { LOCAL(AssertJUnit::assertEquals), DIST((v, r) -> assertEquals(Arrays.asList(v, v), r)); final BiConsumer<String, Object> assertResult; ExecMode(BiConsumer<String, Object> assertResult) { this.assertResult = assertResult; } } }