package com.github.kristofa.test.http;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.commons.lang3.Validate;
/**
* Facade that lets you easily configure and use either the {@link LoggingHttpProxy} for using real services and logging
* requests/responses or the {@link MockHttpServer} for running your code against mocked http requests/responses. </p> You
* can use {@link MockHttpServer} or {@link LoggingHttpProxy} by themselves but if you use both it is most likely that this
* class will make things easier for you.
*
* @author kristof
*/
public class MockAndProxyFacade {
/**
* Specifies the mode in which {@link MockAndProxyFacade} should be operating.
*
* @author kristof
*/
public static enum Mode {
MOCKING, LOGGING
};
public static class Builder {
private static final int MINPORT = 1;
private static final int MAXPORT = 65535;
private int port;
private HttpResponseProvider responseProvider;
private final Collection<ForwardHttpRequestBuilder> requestBuilders = new ArrayList<ForwardHttpRequestBuilder>();
private HttpRequestResponseLoggerFactory loggerFactory;
private Mode mode;
/**
* Sets the port that will be used for either {@link MockHttpServer} or {@link LoggingHttpProxy}.
*
* @param port Port.
* @return Builder.
*/
public Builder port(final int port) {
Validate.inclusiveBetween(MINPORT, MAXPORT, port);
this.port = port;
return this;
}
/**
* Sets the {@link HttpResponseProvider} that will be used for {@link MockHttpServer}.
*
* @param responseProvider {@link HttpResponseProvider}. Should not be <code>null</code>.
* @return Builder.
*/
public Builder httpResponseProvider(final HttpResponseProvider responseProvider) {
Validate.notNull(responseProvider);
this.responseProvider = responseProvider;
return this;
}
/**
* Adds a {@link ForwardHttpRequestBuilder} that will be used with {@link LoggingHttpProxy}.
*
* @param requestBuilder {@link ForwardHttpRequestBuilder}. Should not be <code>null</code>.
* @return Builder.
*/
public Builder addForwardHttpRequestBuilder(final ForwardHttpRequestBuilder requestBuilder) {
Validate.notNull(requestBuilder);
requestBuilders.add(requestBuilder);
return this;
}
/**
* Sets the {@link HttpRequestResponseLoggerFactory} that will be used with {@link LoggingHttpProxy}.
*
* @param loggerFactory {@link HttpRequestResponseLoggerFactory}. Should not be <code>null</code>.
* @return Builder.
*/
public Builder httpRequestResponseLoggerFactory(final HttpRequestResponseLoggerFactory loggerFactory) {
Validate.notNull(loggerFactory);
this.loggerFactory = loggerFactory;
return this;
}
/**
* Sets the Mode in which the {@link MockAndProxyFacade} should operate.
*
* @param mode Operation mode. Should not be <code>null</code>.
* @return Builder.
*/
public Builder mode(final Mode mode) {
Validate.notNull(mode);
this.mode = mode;
return this;
}
public MockAndProxyFacade build() {
return new MockAndProxyFacade(this);
}
}
private final Mode mode;
private MockHttpServer mockServer;
private LoggingHttpProxy proxy;
private MockAndProxyFacade(final Builder builder) {
Validate.notNull(builder.mode, "You should have set mode in builder!");
mode = builder.mode;
Validate.isTrue(builder.port > 0, "You should have set port in builder!");
if (Mode.MOCKING.equals(mode)) {
Validate.notNull(builder.responseProvider,
"You should have set a HttpResponseProvider in builder when using Mocking mode!");
mockServer = new MockHttpServer(builder.port, builder.responseProvider);
} else {
// Logging
Validate.notNull(builder.requestBuilders,
"You should have added a ForwardHttpRequestBuilder when using Logging mode!");
Validate.notNull(builder.loggerFactory,
"You should have set a HttpRequestResponseLoggerFactory when using Logging mode!");
proxy = new LoggingHttpProxy(builder.port, builder.requestBuilders, builder.loggerFactory);
}
}
/**
* Starts either {@link MockHttpServer} or {@link LoggingHttpProxy} depending on operation mode.
*
* @throws IOException In case starting fails.
*/
public void start() throws IOException {
if (Mode.MOCKING.equals(mode)) {
mockServer.start();
} else {
proxy.start();
}
}
/**
* Stops either {@link MockHttpServer} or {@link LoggingHttpProxy} depending on operation mode.
*
* @throws IOException In case stopping fails.
*/
public void stop() throws IOException {
if (Mode.MOCKING.equals(mode)) {
mockServer.stop();
} else {
proxy.stop();
}
}
/**
* In case we are in Mocking operation mode we will verify if all expected requests have been invoked. </p> In case we
* are in Logging operation mode nothing will be checked.
*
* @throws UnsatisfiedExpectationException In case we got unexpected requests and/or not all expected requests were
* invoked.
*/
public void verify() throws UnsatisfiedExpectationException {
if (Mode.MOCKING.equals(mode)) {
mockServer.verify();
}
}
}