package org.infinispan.server.websocket; import static org.infinispan.server.websocket.OpHandler.CACHE_NAME; import static org.infinispan.server.websocket.OpHandler.ERROR; import static org.infinispan.server.websocket.OpHandler.KEY; import static org.infinispan.server.websocket.OpHandler.MIME; import static org.infinispan.server.websocket.OpHandler.OP_CODE; import static org.infinispan.server.websocket.OpHandler.VALUE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.io.IOException; import java.net.ServerSocket; import java.net.URI; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.eclipse.jetty.websocket.WebSocket; import org.eclipse.jetty.websocket.WebSocketClient; import org.eclipse.jetty.websocket.WebSocketClientFactory; import org.infinispan.Cache; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.configuration.global.GlobalConfigurationBuilder; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.server.websocket.configuration.WebSocketServerConfigurationBuilder; import org.infinispan.server.websocket.json.JsonObject; import org.infinispan.test.SingleCacheManagerTest; import org.infinispan.test.fwk.TestCacheManagerFactory; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import net.jcip.annotations.NotThreadSafe; /** * @author gustavonalle */ @Test(testName = "websocket.WebSocketServerIntegrationTest", groups = "functional") public class WebSocketServerIntegrationTest extends SingleCacheManagerTest { private WebSocketServer wsServer; private WebSocketTestClient wsClient; String cacheName = "testCache"; @BeforeMethod public void setUp() throws Exception { Cache<String, String> cache = cacheManager.getCache(cacheName); cache.put("key", "value"); wsServer = new WebSocketServer(); wsServer.start(new WebSocketServerConfigurationBuilder().host("localhost").port(getFreePort()).build(), cacheManager); wsClient = new WebSocketTestClient(cacheName); wsClient.connect(new URI("ws://localhost:" + wsServer.getPort())); } @AfterMethod public void tearDown() throws Exception { wsServer.stop(); wsClient.destroy(); } @Test public void testGet() throws Exception { assertEquals(wsClient.get("key"), "value"); } @Test public void testPut() throws Exception { String key = "key2"; String value = "value2"; wsClient.put(key, value); assertEquals(wsClient.get(key), value); } @Test public void testGarbage() throws Exception { JsonObject jsonObject = wsClient.sendAndWait("garbage"); assertTrue(jsonObject.containsKey(ERROR)); } @Test(expectedExceptions = Exception.class, expectedExceptionsMessageRegExp = "Cache temporarily unavailable") public void testDisableCache() throws Exception { assertEquals(wsClient.get("key"), "value"); wsServer.ignoreCache(cacheName); assertEquals(wsClient.get("key"), "value"); } @NotThreadSafe private static class WebSocketTestClient { private final String cacheName; private final WebSocketClient wsClient; private final WebSocketClientFactory webSocketClientFactory; private CountDownLatch messageLatch = new CountDownLatch(1); private static final int TIMEOUT = 5; private static final TimeUnit TIMEOUT_UNIT = TimeUnit.SECONDS; private WebSocket.Connection connection; private String lastMessage; public WebSocketTestClient(String cacheName) throws Exception { this.cacheName = cacheName; webSocketClientFactory = new WebSocketClientFactory(); webSocketClientFactory.start(); wsClient = webSocketClientFactory.newWebSocketClient(); } public void connect(URI serverURI) throws Exception { connection = wsClient.open(serverURI, new ClientWebSocket()).get(2, TimeUnit.SECONDS); } public void destroy() throws Exception { webSocketClientFactory.stop(); connection.close(); } public void put(String key, String value) throws Exception { JsonObject jsonObject = JsonObject.createNew(); jsonObject.put(OP_CODE, "put"); jsonObject.put(CACHE_NAME, cacheName); jsonObject.put(KEY, key); jsonObject.put(VALUE, value); jsonObject.put(MIME, "text/plain"); connection.sendMessage(jsonObject.toString()); } public JsonObject sendAndWait(String message) throws Exception { messageLatch = new CountDownLatch(1); connection.sendMessage(message); messageLatch.await(TIMEOUT, TIMEOUT_UNIT); return JsonObject.fromString(lastMessage); } private class ClientWebSocket implements WebSocket.OnTextMessage { @Override public void onMessage(String data) { lastMessage = data; messageLatch.countDown(); } @Override public void onOpen(Connection connection) { } @Override public void onClose(int closeCode, String message) { } } public String get(String key) throws Exception { JsonObject jsonObject = JsonObject.createNew(); jsonObject.put(OP_CODE, "get"); jsonObject.put(CACHE_NAME, cacheName); jsonObject.put(KEY, key); JsonObject response = sendAndWait(jsonObject.toString()); if (response.containsKey(ERROR)) { throw new Exception(response.get(ERROR).toString()); } return response.get("value").toString(); } } private int getFreePort() throws IOException { try (ServerSocket socket = new ServerSocket(0)) { return socket.getLocalPort(); } } @Override protected EmbeddedCacheManager createCacheManager() throws Exception { return TestCacheManagerFactory.createCacheManager(new GlobalConfigurationBuilder().defaultCacheName(cacheName), new ConfigurationBuilder()); } }