/*******************************************************************************
* Copyright (c) 2011 Intalio, Inc.
* ======================================================================
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*******************************************************************************/
package org.eclipse.jetty.websocket;
import static org.junit.Assert.*;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.lang.management.ManagementFactory;
import java.net.Socket;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import junit.framework.Assert;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.bio.SocketEndPoint;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class WebSocketLoadD08Test
{
private static Server _server;
private static Connector _connector;
@BeforeClass
public static void startServer() throws Exception
{
_server = new Server();
_connector = new SelectChannelConnector();
_server.addConnector(_connector);
QueuedThreadPool threadPool = new QueuedThreadPool(200);
threadPool.setMaxStopTimeMs(1000);
_server.setThreadPool(threadPool);
WebSocketHandler wsHandler = new WebSocketHandler()
{
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
{
return new EchoWebSocket();
}
};
wsHandler.setHandler(new DefaultHandler());
_server.setHandler(wsHandler);
_server.start();
}
@AfterClass
public static void stopServer() throws Exception
{
_server.stop();
_server.join();
}
@Test
public void testLoad() throws Exception
{
int count = 50;
int iterations = 100;
ExecutorService threadPool = Executors.newCachedThreadPool();
try
{
CountDownLatch latch = new CountDownLatch(count * iterations);
WebSocketClient[] clients = new WebSocketClient[count];
for (int i = 0; i < clients.length; ++i)
{
clients[i] = new WebSocketClient("localhost", _connector.getLocalPort(), 1000, latch, iterations);
clients[i].open();
}
//long start = System.nanoTime();
for (WebSocketClient client : clients)
threadPool.execute(client);
int parallelism = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
long maxTimePerIteration = 5;
assertTrue(latch.await(iterations * (count / parallelism + 1) * maxTimePerIteration, TimeUnit.MILLISECONDS));
//long end = System.nanoTime();
// System.err.println("Elapsed: " + TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
for (WebSocketClient client : clients)
client.close();
}
finally
{
threadPool.shutdown();
assertTrue(threadPool.awaitTermination(2, TimeUnit.SECONDS));
}
}
private static class EchoWebSocket implements WebSocket.OnTextMessage
{
private volatile Connection outbound;
public void onOpen(Connection outbound)
{
this.outbound = outbound;
}
public void onMessage(String data)
{
try
{
// System.err.println(">> "+data);
outbound.sendMessage(data);
}
catch (IOException x)
{
outbound.disconnect();
}
}
public void onClose(int closeCode, String message)
{
}
}
private class WebSocketClient implements Runnable
{
private final Socket socket;
private final BufferedWriter output;
private final BufferedReader input;
private final int iterations;
private final CountDownLatch latch;
private final SocketEndPoint _endp;
private final WebSocketGeneratorD08 _generator;
private final WebSocketParserD08 _parser;
private final WebSocketParser.FrameHandler _handler = new WebSocketParser.FrameHandler()
{
public void onFrame(byte flags, byte opcode, Buffer buffer)
{
_response=buffer;
}
public void close(int code,String message)
{
}
};
private volatile Buffer _response;
public WebSocketClient(String host, int port, int readTimeout, CountDownLatch latch, int iterations) throws IOException
{
this.latch = latch;
socket = new Socket(host, port);
socket.setSoTimeout(readTimeout);
output = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "ISO-8859-1"));
input = new BufferedReader(new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
this.iterations = iterations;
_endp=new SocketEndPoint(socket);
_generator = new WebSocketGeneratorD08(new WebSocketBuffers(32*1024),_endp,new FixedMaskGen());
_parser = new WebSocketParserD08(new WebSocketBuffers(32*1024),_endp,_handler,false);
}
private void open() throws IOException
{
output.write("GET /chat HTTP/1.1\r\n"+
"Host: server.example.com\r\n"+
"Upgrade: websocket\r\n"+
"Connection: Upgrade\r\n"+
"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"+
"Sec-WebSocket-Origin: http://example.com\r\n"+
"Sec-WebSocket-Protocol: onConnect\r\n" +
"Sec-WebSocket-Version: 7\r\n"+
"\r\n");
output.flush();
String responseLine = input.readLine();
assertTrue(responseLine.startsWith("HTTP/1.1 101 Switching Protocols"));
// Read until we find an empty line, which signals the end of the http response
String line;
while ((line = input.readLine()) != null)
if (line.length() == 0)
break;
}
public void run()
{
try
{
String message = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
for (int i = 0; i < iterations; ++i)
{
byte[] data = message.getBytes(StringUtil.__UTF8);
_generator.addFrame((byte)0x8,WebSocketConnectionD08.OP_TEXT,data,0,data.length);
_generator.flush();
//System.err.println("-> "+message);
_response=null;
while(_response==null)
_parser.parseNext();
//System.err.println("<- "+_response);
Assert.assertEquals(message,_response.toString());
latch.countDown();
}
}
catch (IOException x)
{
throw new RuntimeException(x);
}
}
public void close() throws IOException
{
socket.close();
}
}
}