/* * #%L * Wisdom-Framework * %% * Copyright (C) 2013 - 2014 Wisdom Framework * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package org.wisdom.framework.vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpClient; import io.vertx.core.http.HttpClientOptions; import org.junit.After; import org.junit.Test; import org.wisdom.api.configuration.ApplicationConfiguration; import org.wisdom.api.exceptions.ExceptionMapper; import org.wisdom.api.http.websockets.WebSocketListener; import org.wisdom.api.router.Router; import org.wisdom.framework.vertx.file.DiskFileUpload; import java.io.IOException; import java.util.Collections; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * Test the web socket management. */ public class WebSocketTest extends VertxBaseTest { private WisdomVertxServer server; @After public void tearDown() { if (server != null) { server.stop(); server = null; } } @Test public void testPingPong() throws InterruptedException, IOException { prepareServer(); Spy spy = new Spy(server); server.register(spy); final CountDownLatch done = new CountDownLatch(1); final StringBuilder marker = new StringBuilder(); HttpClient client = vertx.createHttpClient(new HttpClientOptions().setDefaultHost("localhost") .setDefaultPort(server.httpPort())); client.websocket("/some-uri", ws -> { ws.handler(event -> { if (event.toString().equals("pong")) { marker.append("pong"); done.countDown(); } }); ws.write(Buffer.buffer("ping")); }); done.await(30, TimeUnit.SECONDS); assertThat(marker).containsOnlyOnce("pong"); client.close(); } @Test public void testMultipleP2PPingPong() throws InterruptedException, IOException { prepareServer(); Spy spy = new Spy(server); server.register(spy); // Now start bunch of clients int num = NUMBER_OF_CLIENTS; final CountDownLatch startSignal = new CountDownLatch(1); final CountDownLatch doneSignal = new CountDownLatch(num); for (int i = 1; i < num + 1; ++i) { final int id = i; executor.submit(() -> { try { startSignal.await(); HttpClientOptions options = new HttpClientOptions() .setDefaultHost("localhost") .setDefaultPort(server.httpPort()); vertx.createHttpClient(options) .websocket("/some-uri", ws -> { ws.handler(event -> { if (event.toString().equals("" + id)) { success(id); } else { fail(id); } doneSignal.countDown(); }); ws.write(Buffer.buffer("" + id)); }); } catch (Throwable ex) { ex.printStackTrace(); fail(id); } }); } startSignal.countDown(); // let all threads proceed doneSignal.await(60, TimeUnit.SECONDS); // wait for all to finish assertThat(failure).isEmpty(); assertThat(success).hasSize(num); } @Test public void testBroadcast() throws InterruptedException, IOException { prepareServer(); // Now start bunch of clients int num = NUMBER_OF_CLIENTS; final CountDownLatch preparedSignal = new CountDownLatch(num); final CountDownLatch doneSignal = new CountDownLatch(num); for (int i = 1; i < num + 1; ++i) { final int id = i; executor.submit(() -> { try { HttpClientOptions options = new HttpClientOptions() .setDefaultHost("localhost") .setDefaultPort(server.httpPort()); HttpClient client = vertx.createHttpClient(options); client.websocket("/some-uri", ws -> { preparedSignal.countDown(); ws.handler(event -> { if (event.toString().equals("hello")) { success(id); } else { fail(id); } doneSignal.countDown(); }); }); } catch (Throwable ex) { ex.printStackTrace(); fail(id); } }); } // startSignal.countDown(); // let all threads proceed preparedSignal.await(30, TimeUnit.SECONDS); server.publish("/some-uri", "hello"); doneSignal.await(60, TimeUnit.SECONDS); // wait for all to finish assertThat(failure).isEmpty(); assertThat(success).hasSize(num); } private void prepareServer() throws InterruptedException, IOException { // Prepare the configuration ApplicationConfiguration configuration = mock(ApplicationConfiguration.class); when(configuration.getIntegerWithDefault(eq("vertx.http.port"), anyInt())).thenReturn(0); when(configuration.getIntegerWithDefault(eq("vertx.https.port"), anyInt())).thenReturn(-1); when(configuration.getIntegerWithDefault("vertx.receiveBufferSize", -1)).thenReturn(-1); when(configuration.getIntegerWithDefault("vertx.sendBufferSize", -1)).thenReturn(-1); when(configuration.getLongWithDefault("http.upload.disk.threshold", DiskFileUpload.MINSIZE)).thenReturn (DiskFileUpload.MINSIZE); when(configuration.getLongWithDefault("http.upload.max", -1L)).thenReturn(-1L); when(configuration.getIntegerWithDefault("vertx.acceptBacklog", -1)).thenReturn(-1); when(configuration.getIntegerWithDefault("vertx.maxWebSocketFrameSize", -1)).thenReturn(-1); when(configuration.getStringArray("wisdom.websocket.subprotocols")).thenReturn(new String[0]); when(configuration.getStringArray("vertx.websocket-subprotocols")).thenReturn(new String[0]); // Configure the server. server = new WisdomVertxServer(); server.accessor = new ServiceAccessor( null, configuration, mock(Router.class), getMockContentEngine(), executor, server, Collections.<ExceptionMapper>emptyList() ); server.vertx = vertx; server.configuration = configuration; server.start(); VertxHttpServerTest.waitForStart(server); } private class Spy implements WebSocketListener { private final WisdomVertxServer server; public Spy(WisdomVertxServer server) { this.server = server; } @Override public void received(String uri, String client, byte[] content) { if (new String(content).equalsIgnoreCase("ping")) { server.send(uri, client, "pong"); } else { // Echo server.send(uri, client, content); } } @Override public void opened(String uri, String client) { } @Override public void closed(String uri, String client) { } } }