/*
* Copyright (C) 2015 SoftIndex LLC.
*
* 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.
*/
package io.datakernel.http;
import io.datakernel.async.IgnoreCompletionCallback;
import io.datakernel.async.ResultCallback;
import io.datakernel.async.ResultCallbackFuture;
import io.datakernel.bytebuf.ByteBuf;
import io.datakernel.bytebuf.ByteBufPool;
import io.datakernel.bytebuf.ByteBufStrings;
import io.datakernel.eventloop.AsyncTcpSocket;
import io.datakernel.eventloop.Eventloop;
import io.datakernel.eventloop.SimpleServer;
import io.datakernel.eventloop.SimpleServer.SocketHandlerProvider;
import io.datakernel.exception.AsyncTimeoutException;
import io.datakernel.exception.ParseException;
import org.junit.Before;
import org.junit.Test;
import java.net.InetAddress;
import java.util.concurrent.ExecutionException;
import static io.datakernel.bytebuf.ByteBufPool.*;
import static io.datakernel.bytebuf.ByteBufStrings.decodeUtf8;
import static io.datakernel.bytebuf.ByteBufStrings.encodeAscii;
import static io.datakernel.eventloop.FatalErrorHandlers.rethrowOnAnyError;
import static org.junit.Assert.assertEquals;
public class AsyncHttpClientTest {
private static final int PORT = 45788;
public static final byte[] TIMEOUT_EXCEPTION_BYTES = encodeAscii("ERROR: Must be TimeoutException");
private static final InetAddress GOOGLE_PUBLIC_DNS = HttpUtils.inetAddress("8.8.8.8");
@Before
public void before() {
ByteBufPool.clear();
ByteBufPool.setSizes(0, Integer.MAX_VALUE);
}
@Test
public void testAsyncClient() throws Exception {
final Eventloop eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError());
final AsyncHttpServer httpServer = HelloWorldServer.helloWorldServer(eventloop, PORT);
final AsyncHttpClient httpClient = AsyncHttpClient.create(eventloop);
final ResultCallbackFuture<String> resultObserver = ResultCallbackFuture.create();
httpServer.listen();
httpClient.send(HttpRequest.get("http://127.0.0.1:" + PORT), new ResultCallback<HttpResponse>() {
@Override
public void onResult(final HttpResponse result) {
try {
resultObserver.setResult(decodeUtf8(result.getBody()));
} catch (ParseException e) {
onException(e);
}
httpClient.stop(IgnoreCompletionCallback.create());
httpServer.close(IgnoreCompletionCallback.create());
}
@Override
public void onException(Exception exception) {
resultObserver.setException(exception);
httpClient.stop(IgnoreCompletionCallback.create());
httpServer.close(IgnoreCompletionCallback.create());
}
});
eventloop.run();
assertEquals(decodeUtf8(HelloWorldServer.HELLO_WORLD), resultObserver.get());
assertEquals(getPoolItemsString(), ByteBufPool.getCreatedItems(), ByteBufPool.getPoolItems());
}
@Test(expected = AsyncTimeoutException.class)
public void testClientTimeoutConnect() throws Throwable {
final int TIMEOUT = 1;
final Eventloop eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError());
final AsyncHttpClient httpClient = AsyncHttpClient.create(eventloop).withConnectTimeout(TIMEOUT);
final ResultCallbackFuture<String> resultObserver = ResultCallbackFuture.create();
httpClient.send(HttpRequest.get("http://google.com"), new ResultCallback<HttpResponse>() {
@Override
public void onResult(HttpResponse result) {
try {
resultObserver.setResult(decodeUtf8(result.getBody()));
} catch (ParseException e) {
onException(e);
}
httpClient.stop(IgnoreCompletionCallback.create());
}
@Override
public void onException(Exception exception) {
resultObserver.setException(exception);
httpClient.stop(IgnoreCompletionCallback.create());
}
});
eventloop.run();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
try {
System.err.println("Result: " + resultObserver.get());
} catch (ExecutionException e) {
throw e.getCause();
}
}
@Test(expected = ParseException.class)
public void testBigHttpMessage() throws Throwable {
final Eventloop eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError());
final AsyncHttpServer httpServer = HelloWorldServer.helloWorldServer(eventloop, PORT);
final AsyncHttpClient httpClient = AsyncHttpClient.create(eventloop)
.withMaxHttpMessageSize(12);
final ResultCallbackFuture<String> resultObserver = ResultCallbackFuture.create();
httpServer.listen();
httpClient.send(HttpRequest.get("http://127.0.0.1:" + PORT), new ResultCallback<HttpResponse>() {
@Override
public void onResult(HttpResponse result) {
try {
resultObserver.setResult(decodeUtf8(result.getBody()));
} catch (ParseException e) {
onException(e);
}
httpClient.stop(IgnoreCompletionCallback.create());
httpServer.close(IgnoreCompletionCallback.create());
}
@Override
public void onException(Exception exception) {
resultObserver.setException(exception);
httpClient.stop(IgnoreCompletionCallback.create());
httpServer.close(IgnoreCompletionCallback.create());
}
});
eventloop.run();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
try {
System.err.println("Result: " + resultObserver.get());
} catch (ExecutionException e) {
throw e.getCause();
}
}
@Test(expected = ParseException.class)
public void testEmptyLineResponse() throws Throwable {
final Eventloop eventloop = Eventloop.create().withFatalErrorHandler(rethrowOnAnyError());
final SocketHandlerProvider socketHandlerProvider = new SocketHandlerProvider() {
@Override
public AsyncTcpSocket.EventHandler createSocketHandler(final AsyncTcpSocket asyncTcpSocket) {
return new AsyncTcpSocket.EventHandler() {
@Override
public void onRegistered() {
asyncTcpSocket.read();
}
@Override
public void onRead(ByteBuf buf) {
buf.recycle();
asyncTcpSocket.write(ByteBufStrings.wrapAscii("\r\n"));
}
@Override
public void onReadEndOfStream() {
// empty
}
@Override
public void onWrite() {
asyncTcpSocket.close();
}
@Override
public void onClosedWithError(Exception e) {
// empty
}
};
}
};
final SimpleServer server = SimpleServer.create(eventloop, socketHandlerProvider).withListenPort(PORT);
final AsyncHttpClient httpClient = AsyncHttpClient.create(eventloop);
final ResultCallbackFuture<String> resultObserver = ResultCallbackFuture.create();
server.listen();
httpClient.send(HttpRequest.get("http://127.0.0.1:" + PORT), new ResultCallback<HttpResponse>() {
@Override
public void onResult(HttpResponse result) {
try {
resultObserver.setResult(decodeUtf8(result.getBody()));
} catch (ParseException e) {
onException(e);
}
httpClient.stop(IgnoreCompletionCallback.create());
}
@Override
public void onException(Exception e) {
resultObserver.setException(e);
httpClient.stop(IgnoreCompletionCallback.create());
server.close(IgnoreCompletionCallback.create());
}
});
eventloop.run();
assertEquals(getPoolItemsString(), getCreatedItems(), getPoolItems());
try {
System.err.println("Result: " + resultObserver.get());
} catch (ExecutionException e) {
throw e.getCause();
}
}
}