blob: 7849f49abb79fa28f8da4f33e4f945a3b3dc05c6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
package org.apache.tomcat.lite.load;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import junit.framework.TestCase;
import org.apache.tomcat.lite.TestMain;
import org.apache.tomcat.lite.http.HttpClient;
import org.apache.tomcat.lite.http.HttpChannel;
import org.apache.tomcat.lite.http.HttpConnector;
import org.apache.tomcat.lite.http.HttpRequest;
import org.apache.tomcat.lite.http.HttpChannel.RequestCompleted;
import org.apache.tomcat.lite.io.BBuffer;
import org.apache.tomcat.lite.io.SocketConnector;
/*
Notes on memory use ( from heap dumps ):
- buffers are not yet recycled ( the BBuffers used in channels )
- each active connection consumes at least 26k - 2 buffers + head buffer
( 8k each )
TODO: could 'peak' in the In buffer and move headRecv to HttpChannel
- HttpChannel keeps about 64K ( for the hello world ).
-- res is 25k
-- req is 32k, BufferedIOReader 16k,
TODO:
- leak in NioThread.active - closed sockets not removed
- need to rate-limit and queue requests - OOM
- timeouts
- seems few responses missing on large async requests (URL works)
*/
/**
* Long running test - async tests are failing since rate control
* is not implemented ( too many outstanding requests - OOM ),
* it seems there is a bug as well.
*/
public class LiveHttpThreadedTest extends TestCase {
HttpConnector clientCon = TestMain.shared().getClient();
HttpConnector serverCon = TestMain.shared().getTestServer();
HttpConnector spdyClient =
HttpClient.newClient().setCompression(false);
HttpConnector spdyClientCompress =
HttpClient.newClient();
HttpConnector spdyClientCompressSsl =
HttpClient.newClient();
ThreadRunner tr;
static boolean dumpHeap = true;
AtomicInteger ok = new AtomicInteger();
int reqCnt;
Map<HttpRequest, HttpRequest> active = new HashMap();
public void tearDown() throws IOException {
clientCon.cpool.clear();
}
public void test1000Async() throws Exception {
// try {
asyncRequest(10, 100, false, false, clientCon, "AsyncHttp");
// } finally {
// dumpHeap("heapAsync.bin");
// }
}
public void test10000Async() throws Exception {
asyncRequest(20, 500, false, false, clientCon, "AsyncHttp");
}
public void test1000AsyncSsl() throws Exception {
asyncRequest(20, 50, false, true, clientCon, "AsyncHttpSsl");
}
public void test10000AsyncSsl() throws Exception {
asyncRequest(20, 500, false, true, clientCon, "AsyncHttpSsl");
}
public void test1000AsyncSpdy() throws Exception {
asyncRequest(10, 100, true, false, spdyClient, "AsyncSpdy");
}
public void test10000AsyncSpdy() throws Exception {
asyncRequest(20, 500, true, false, spdyClient, "AsyncSpdy");
}
public void test1000AsyncSpdyComp() throws Exception {
asyncRequest(10, 100, true, false, spdyClientCompress, "AsyncSpdyComp");
}
public void test10000AsyncSpdyComp() throws Exception {
asyncRequest(20, 500, true, false, spdyClientCompress, "AsyncSpdyComp");
}
public void xtest1000AsyncSpdySsl() throws Exception {
asyncRequest(10, 100, true, true, spdyClient, "AsyncSpdySsl");
}
public void xtest1000AsyncSpdyCompSsl() throws Exception {
asyncRequest(10, 100, true, true, spdyClientCompress, "AsyncSpdyCompSsl");
}
public void xtest10000AsyncSpdyCompSsl() throws Exception {
asyncRequest(20, 500, true, true, spdyClientCompress, "AsyncSpdyCompSsl");
}
Object thrlock = new Object();
Object lock = new Object();
public void asyncRequest(final int thr, int perthr,
final boolean spdy, final boolean ssl,
final HttpConnector clientCon, String test) throws Exception {
clientCon.getConnectionPool().clear();
reqCnt = thr * perthr;
long t0 = System.currentTimeMillis();
tr = new ThreadRunner(thr, perthr) {
public void makeRequest(int i) throws Exception {
HttpRequest cstate = clientCon.request("localhost",
ssl ? 8443 : 8802);
synchronized (active) {
active.put(cstate, cstate);
}
if (spdy) {
// Magic way to force spdy - will be replaced with
// a negotiation.
cstate.setProtocol("SPDY/1.0");
}
if (ssl) {
cstate.setSecure(true);
}
cstate.requestURI().set("/hello");
cstate.setCompletedCallback(reqCallback);
// no body
cstate.getBody().close();
cstate.send();
while (active.size() >= thr) {
synchronized(thrlock) {
thrlock.wait();
}
}
}
};
tr.run();
synchronized (lock) {
if (ok.get() < reqCnt) {
lock.wait(reqCnt * 100);
}
}
long time = (System.currentTimeMillis() - t0);
System.err.println("====== " + test +
" threads: " + thr + ", req: " +
reqCnt + ", sendTime" + tr.time +
", time: " + time +
", connections: " + clientCon.getConnectionPool().getSocketCount() +
", avg: " + (time / reqCnt));
assertEquals(reqCnt, ok.get());
assertEquals(0, tr.errors.get());
}
RequestCompleted reqCallback = new RequestCompleted() {
@Override
public void handle(HttpChannel data, Object extraData)
throws IOException {
String out = data.getIn().copyAll(null).toString();
if (200 != data.getResponse().getStatus()) {
System.err.println("Wrong status");
tr.errors.incrementAndGet();
} else if (!"Hello world".equals(out)) {
tr.errors.incrementAndGet();
System.err.println("bad result " + out);
}
synchronized (active) {
active.remove(data.getRequest());
}
synchronized (thrlock) {
thrlock.notify();
}
data.release();
int okres = ok.incrementAndGet();
if (okres >= reqCnt) {
synchronized (lock) {
lock.notify();
}
}
}
};
public void testURLRequest1000() throws Exception {
urlRequest(10, 100, false, "HttpURLConnection");
}
public void xtestURLRequest10000() throws Exception {
urlRequest(20, 500, false, "HttpURLConnection");
}
// I can't seem to get 1000 requests to all complete...
public void xtestURLRequestSsl100() throws Exception {
urlRequest(10, 10, true, "HttpURLConnectionSSL");
}
public void xtestURLRequestSsl10000() throws Exception {
urlRequest(20, 500, true, "HttpURLConnectionSSL");
}
/**
* HttpURLConnection client against lite.http server.
*/
public void urlRequest(int thr, int cnt, final boolean ssl, String test)
throws Exception {
long t0 = System.currentTimeMillis();
try {
HttpConnector testServer = TestMain.getTestServer();
tr = new ThreadRunner(thr, cnt) {
public void makeRequest(int i) throws Exception {
try {
BBuffer out = BBuffer.allocate();
String url = ssl ? "https://localhost:8443/hello" :
"http://localhost:8802/hello";
HttpURLConnection con =
TestMain.getUrl(url, out);
if (con.getResponseCode() != 200) {
errors.incrementAndGet();
}
if (!"Hello world".equals(out.toString())) {
errors.incrementAndGet();
System.err.println("bad result " + out);
}
} catch(Throwable t) {
t.printStackTrace();
errors.incrementAndGet();
}
}
};
tr.run();
assertEquals(0, tr.errors.get());
long time = (System.currentTimeMillis() - t0);
System.err.println("====== " + test + " threads: " + thr + ", req: " +
(thr * cnt) + ", time: " + time + ", avg: " +
(time / (thr * cnt)));
} finally {
//dumpHeap("heapURLReq.bin");
}
}
// TODO: move to a servlet
}