Skip to content

Commit

Permalink
#257 further clean-up and integration tests for harmonizing mocking a…
Browse files Browse the repository at this point in the history
…nd proxy logic
  • Loading branch information
jamesdbloom committed Dec 25, 2017
1 parent ccda7ee commit 40887b2
Show file tree
Hide file tree
Showing 43 changed files with 890 additions and 303 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import org.mockserver.client.netty.NettyHttpClient;
import org.mockserver.client.netty.SocketConnectionException;
import org.mockserver.client.serialization.*;
import org.mockserver.client.server.ClientException;
import org.mockserver.matchers.TimeToLive;
import org.mockserver.matchers.Times;
import org.mockserver.mock.Expectation;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package org.mockserver.client.server;
package org.mockserver.client;

/**
* @author jamesdbloom
*/
public class ClientException extends RuntimeException {

public ClientException(String message, Throwable cause) {
super(message, cause);
}

public ClientException(String message) {
super(message);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.mockserver.client.ClientException;
import org.mockserver.echo.http.EchoServer;
import org.mockserver.socket.PortFactory;

import static org.hamcrest.Matchers.containsString;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.mockserver.character.Character.NEW_LINE;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ private InetSocketAddress socketAddressFromHostHeader(HttpRequest request) {
if (!Strings.isNullOrEmpty(request.getFirstHeader(HOST.toString()))) {
boolean isSsl = request.isSecure() != null && request.isSecure();
String[] hostHeaderParts = request.getFirstHeader(HOST.toString()).split(":");
return new InetSocketAddress(hostHeaderParts[0], hostHeaderParts.length > 1 ? Integer.parseInt(hostHeaderParts[1]) : isSsl ? 443 : 80
);
return new InetSocketAddress(hostHeaderParts[0], hostHeaderParts.length > 1 ? Integer.parseInt(hostHeaderParts[1]) : isSsl ? 443 : 80);
} else {
throw new IllegalArgumentException("Host header must be provided for requests being forwarded, the following request does not include the \"Host\" header:" + NEW_LINE + request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ public class EchoServer {

static final AttributeKey<LogFilter> LOG_FILTER = AttributeKey.valueOf("SERVER_LOG_FILTER");
static final AttributeKey<NextResponse> NEXT_RESPONSE = AttributeKey.valueOf("NEXT_RESPONSE");
static final AttributeKey<OnlyResponse> ONLY_RESPONSE = AttributeKey.valueOf("ONLY_RESPONSE");

private final LogFilter logFilter = new LogFilter(new LoggingFormatter(LoggerFactory.getLogger(this.getClass()), null));
private final NextResponse nextResponse = new NextResponse();
private final OnlyResponse onlyResponse = new OnlyResponse();
private final NioEventLoopGroup eventLoopGroup = new NioEventLoopGroup();


Expand All @@ -52,6 +54,7 @@ public void run() {
.childHandler(new EchoServerInitializer(secure, error))
.childAttr(LOG_FILTER, logFilter)
.childAttr(NEXT_RESPONSE, nextResponse)
.childAttr(ONLY_RESPONSE, onlyResponse)
.bind(port)
.addListener(new ChannelFutureListener() {
@Override
Expand Down Expand Up @@ -90,6 +93,12 @@ public EchoServer withNextResponse(HttpResponse... httpResponses) {
return this;
}

public EchoServer withOnlyResponse(HttpResponse httpResponse) {
// WARNING: this logic is only for unit tests that run in series and is NOT thread safe!!!
onlyResponse.httpResponse = httpResponse;
return this;
}

public enum Error {
CLOSE_CONNECTION,
LARGER_CONTENT_LENGTH,
Expand All @@ -100,4 +109,8 @@ public enum Error {
public class NextResponse {
public final Queue<HttpResponse> httpResponse = new LinkedList<HttpResponse>();
}

public class OnlyResponse {
public HttpResponse httpResponse;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ public class EchoServerHandler extends SimpleChannelInboundHandler<HttpRequest>
private final EchoServer.Error error;
private final LogFilter logFilter;
private final EchoServer.NextResponse nextResponse;
private final EchoServer.OnlyResponse onlyResponse;

public EchoServerHandler(EchoServer.Error error, LogFilter logFilter, EchoServer.NextResponse nextResponse) {
EchoServerHandler(EchoServer.Error error, LogFilter logFilter, EchoServer.NextResponse nextResponse, EchoServer.OnlyResponse onlyResponse) {
this.error = error;
this.logFilter = logFilter;
this.nextResponse = nextResponse;
this.onlyResponse = onlyResponse;
}

protected void channelRead0(ChannelHandlerContext ctx, HttpRequest request) {
Expand All @@ -41,7 +43,11 @@ protected void channelRead0(ChannelHandlerContext ctx, HttpRequest request) {

logFilter.onRequest(new RequestLogEntry(request));

if (!nextResponse.httpResponse.isEmpty()) {
if (onlyResponse.httpResponse != null) {
// WARNING: this logic is only for unit tests that run in series and is NOT thread safe!!!
DefaultFullHttpResponse httpResponse = new MockServerResponseEncoder().encode(onlyResponse.httpResponse);
ctx.writeAndFlush(httpResponse);
} else if (!nextResponse.httpResponse.isEmpty()) {
// WARNING: this logic is only for unit tests that run in series and is NOT thread safe!!!
DefaultFullHttpResponse httpResponse = new MockServerResponseEncoder().encode(nextResponse.httpResponse.remove());
ctx.writeAndFlush(httpResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import static org.mockserver.echo.http.EchoServer.LOG_FILTER;
import static org.mockserver.echo.http.EchoServer.NEXT_RESPONSE;
import static org.mockserver.echo.http.EchoServer.ONLY_RESPONSE;
import static org.mockserver.socket.NettySslContextFactory.nettySslContextFactory;

/**
Expand Down Expand Up @@ -56,6 +57,15 @@ public void initChannel(SocketChannel channel) throws Exception {

pipeline.addLast(new MockServerServerCodec(secure));

pipeline.addLast(new EchoServerHandler(error, channel.attr(LOG_FILTER).get(), channel.attr(NEXT_RESPONSE).get()));
if (!secure && error == EchoServer.Error.CLOSE_CONNECTION) {
throw new IllegalArgumentException("Error type CLOSE_CONNECTION is not supported in non-secure mode");
}

pipeline.addLast(new EchoServerHandler(
error,
channel.attr(LOG_FILTER).get(),
channel.attr(NEXT_RESPONSE).get(),
channel.attr(ONLY_RESPONSE).get()
));
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
package org.mockserver.server.unification;
package org.mockserver.echo.unification;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.ssl.SslHandler;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpResponseStatus.*;
import static io.netty.handler.codec.http.HttpUtil.is100ContinueExpected;
import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import static org.mockserver.socket.NettySslContextFactory.nettySslContextFactory;

/**
* @author jamesdbloom
*/
@ChannelHandler.Sharable
public abstract class PortUnificationHandler extends SimpleChannelInboundHandler<ByteBuf> {
public class EchoServerPortUnificationHandler extends SimpleChannelInboundHandler<ByteBuf> {

public static final AttributeKey<Boolean> SSL_ENABLED = AttributeKey.valueOf("SSL_ENABLED");
private static final AttributeKey<Boolean> SSL_ENABLED = AttributeKey.valueOf("SSL_ENABLED");
private final Logger logger = LoggerFactory.getLogger(this.getClass());

public PortUnificationHandler() {
EchoServerPortUnificationHandler() {
super(false);
}

@Override
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) {
// Will use the first five bytes to detect a protocol.
if (msg.readableBytes() < 3) {
return;
Expand Down Expand Up @@ -80,7 +84,7 @@ private boolean isHttp(ByteBuf msg) {
private void enableSsl(ChannelHandlerContext ctx, ByteBuf msg) {
ChannelPipeline pipeline = ctx.pipeline();
pipeline.addFirst(nettySslContextFactory().createServerSslContext().newHandler(ctx.alloc()));
ctx.channel().attr(PortUnificationHandler.SSL_ENABLED).set(Boolean.TRUE);
ctx.channel().attr(SSL_ENABLED).set(Boolean.TRUE);

// re-unify (with SSL enabled)
ctx.pipeline().fireChannelRead(msg);
Expand All @@ -91,23 +95,52 @@ private void switchToHttp(ChannelHandlerContext ctx, ByteBuf msg) {

addLastIfNotPresent(pipeline, new HttpServerCodec(8192, 8192, 8192));
addLastIfNotPresent(pipeline, new HttpContentDecompressor());
addLastIfNotPresent(pipeline, new HttpContentLengthRemover());
addLastIfNotPresent(pipeline, new HttpObjectAggregator(Integer.MAX_VALUE));
if (logger.isDebugEnabled()) {
addLastIfNotPresent(pipeline, new LoggingHandler());
addLastIfNotPresent(pipeline, new io.netty.handler.logging.LoggingHandler());
}
configurePipeline(ctx, pipeline);
configurePipeline(pipeline);
pipeline.remove(this);

// fire message back through pipeline
ctx.fireChannelRead(msg);
}

protected void addLastIfNotPresent(ChannelPipeline pipeline, ChannelHandler channelHandler) {
private void addLastIfNotPresent(ChannelPipeline pipeline, ChannelHandler channelHandler) {
if (pipeline.get(channelHandler.getClass()) == null) {
pipeline.addLast(channelHandler);
}
}

protected abstract void configurePipeline(ChannelHandlerContext ctx, ChannelPipeline pipeline);
private void configurePipeline(ChannelPipeline pipeline) {
pipeline.addLast(new SimpleChannelInboundHandler<FullHttpRequest>() {

protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
HttpResponseStatus responseStatus = OK;
if (request.uri().equals("/not_found")) {
responseStatus = NOT_FOUND;
}
// echo back request headers and body
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, responseStatus, Unpooled.copiedBuffer(request.content()));
response.headers().add(request.headers());

// set hop-by-hop headers
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
if (isKeepAlive(request)) {
response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
if (is100ContinueExpected(request)) {
ctx.write(new DefaultFullHttpResponse(HTTP_1_1, CONTINUE));
}

// write and flush
ctx.writeAndFlush(response);
}

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
});
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void run() {
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler("EchoServer Handler"))
.childHandler(new EchoServerUnificationHandler())
.childHandler(new EchoServerPortUnificationHandler())
.bind(port)
.addListener(new ChannelFutureListener() {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@
*/
public class HttpServletRequestToMockServerRequestDecoder {
public HttpRequest mapHttpServletRequestToMockServerRequest(HttpServletRequest httpServletRequest) {
HttpRequest httpRequest = new HttpRequest();
setMethod(httpRequest, httpServletRequest);
HttpRequest request = new HttpRequest();
setMethod(request, httpServletRequest);

setPath(httpRequest, httpServletRequest);
setQueryString(httpRequest, httpServletRequest);
setPath(request, httpServletRequest);
setQueryString(request, httpServletRequest);

setBody(httpRequest, httpServletRequest);
setHeaders(httpRequest, httpServletRequest);
setCookies(httpRequest, httpServletRequest);
setBody(request, httpServletRequest);
setHeaders(request, httpServletRequest);
setCookies(request, httpServletRequest);

httpRequest.withKeepAlive(isKeepAlive(httpServletRequest));
httpRequest.withSecure(httpServletRequest.isSecure());
return httpRequest;
request.withKeepAlive(isKeepAlive(httpServletRequest));
request.withSecure(httpServletRequest.isSecure());
return request;
}

private void setMethod(HttpRequest httpRequest, HttpServletRequest httpServletRequest) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.base.Function;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import io.netty.util.AttributeKey;
import org.apache.commons.lang3.StringUtils;
import org.mockserver.client.serialization.ExpectationSerializer;
import org.mockserver.client.serialization.HttpRequestSerializer;
Expand Down Expand Up @@ -39,6 +40,7 @@
*/
public class HttpStateHandler {

public static final AttributeKey<HttpStateHandler> STATE_HANDLER = AttributeKey.valueOf("PROXY_STATE_HANDLER");
public static final String LOG_SEPARATOR = "------------------------------------\n";
// mockserver
private LoggingFormatter logFormatter = new LoggingFormatter(LoggerFactory.getLogger(this.getClass()), this);
Expand Down
Loading

0 comments on commit 40887b2

Please sign in to comment.