Skip to content

Instantly share code, notes, and snippets.

@mressler
Created February 6, 2015 18:30
Show Gist options
  • Save mressler/2802b547ef6feac6c8ad to your computer and use it in GitHub Desktop.
Save mressler/2802b547ef6feac6c8ad to your computer and use it in GitHub Desktop.
HttpTestServer Additions
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.Semaphore;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.junit.Ignore;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
/**
* A server for answering HTTP requests with test response data.
*
* @see http://olafsblog.sysbsb.de/lightweight-testing-of-webservice-http-clients-with-junit-and-jetty/
* @see http://www.eclipse.org/jetty/documentation/current/jetty-handlers.html#writing-custom-handlers
*/
@Ignore
public class HttpTestServer {
public static final int HTTP_PORT = 50036;
private int port;
private Server server;
private ArrayList<ExpectedRequestAndResponse> expectations;
private boolean unexpectedQueryReceived;
public HttpTestServer() {
this.port = HTTP_PORT;
this.expectations = new ArrayList<>();
}
public HttpTestServer(Integer port) {
this.port = port;
this.expectations = new ArrayList<>();
}
public void addExpectation(ExpectedRequestAndResponse expectation) {
expectations.add(expectation);
}
public void start() throws Exception {
configureServer();
startServer();
}
private void startServer() throws Exception {
server.start();
}
protected void configureServer() {
server = new Server(HTTP_PORT);
server.setHandler(getMockHandler());
}
/**
* Creates an {@link AbstractHandler handler} returning an arbitrary String as a response.
*
* @return never <code>null</code>.
*/
public Handler getMockHandler() {
Handler handler = new AbstractHandler() {
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
if (expectations.size() == 0) {
unexpectedQueryReceived = true;
}
boolean matchFound = false;
Iterator<ExpectedRequestAndResponse> iter = expectations.iterator();
while (iter.hasNext() && !matchFound) {
ExpectedRequestAndResponse possibleMatch = iter.next();
if (possibleMatch.matches(target, request.getMethod())) {
response.setContentType(possibleMatch.contentType);
response.setStatus(possibleMatch.responseStatus.value());
response.getWriter().println(possibleMatch.responseBody);
String requestBody = IOUtils.toString(request.getInputStream());
possibleMatch.expectationMet(requestBody);
iter.remove();
matchFound = true;
} else {
possibleMatch.passedOver();
}
}
baseRequest.setHandled(true);
}
};
return handler;
}
public boolean allExpectationsMet() {
boolean allMet = true;
for (ExpectedRequestAndResponse expectation : expectations) {
allMet = allMet && expectation.isMet();
}
return allMet;
}
public void resetExpectations() {
expectations.clear();
}
public boolean unexpectedQueryReceived() {
return unexpectedQueryReceived;
}
public void stop() throws Exception {
server.stop();
}
public int getPort() {
return port;
}
public static class ExpectedRequestAndResponse {
int failAfter;
String onUri;
HttpMethod withMethod;
String responseBody;
HttpStatus responseStatus;
String contentType;
private String requestBody;
private boolean met;
Semaphore expectLock;
public ExpectedRequestAndResponse(String onUri) {
init(onUri, HttpMethod.POST, "OK", HttpStatus.OK, MediaType.TEXT_PLAIN, 1);
}
public ExpectedRequestAndResponse(
String onUri, HttpMethod withMethod,
String responseBody, HttpStatus responseStatus, String contentType)
{
init(onUri, withMethod, responseBody, responseStatus, contentType, 1);
}
public boolean isMet() {
if (!met) {
fail("Expectation for " + withMethod + " - " + onUri + " was never met");
}
return met;
}
public ExpectedRequestAndResponse(
String onUri, HttpMethod withMethod,
String responseBody, HttpStatus responseStatus, String contentType,
int failAfter)
{
init(onUri, withMethod, responseBody, responseStatus, contentType, failAfter);
}
private void init(
String onUri, HttpMethod withMethod,
String responseBody, HttpStatus responseStatus, String contentType,
int failAfter)
{
this.onUri = onUri;
this.withMethod = withMethod;
this.responseBody = responseBody;
this.responseStatus = responseStatus;
this.contentType = contentType;
this.failAfter = failAfter;
expectLock = new Semaphore(0);
met = false;
}
public String waitForResponse() throws InterruptedException {
expectLock.acquire();
return requestBody;
}
public void expectationMet(String requestBody) {
this.requestBody = requestBody;
this.met = true;
expectLock.release();
}
public boolean matches(String target, String method) {
return target.equalsIgnoreCase(onUri) && method.equals(withMethod.name());
}
public void passedOver() {
failAfter--;
if (failAfter == 0) {
expectLock.release(); // <-- so the tests don't sit waiting on an object that will never come true
}
}
}
}
public class UnitTest {
@BeforeClass
public static void setUp() throws Exception {
server = new HttpTestServer();
server.start();
}
@AfterClass
public static void tearDown() throws Exception {
server.stop();
}
@Before
public void before() {
server.resetExpectations();
}
@Test
public thatConnectionsCanBeMade() {
// Now alert the server about the data it's about to receive.
ExpectedRequestAndResponse user1Expectation = new ExpectedRequestAndResponse(user1Uri);
server.addExpectation(user1Expectation);
ExpectedRequestAndResponse user2Expectation = new ExpectedRequestAndResponse(user2Uri);
server.addExpectation(user2Expectation);
// Confirm the connection
connectionResponse = template.exchange(
"http://localhost:8080/" + SwingTrackerRequestMappings.USER_CONNECTION,
HttpMethod.POST,
new HttpEntity<UserToUserConnectionDTO>(null, user2.headers),
UserToUserConnectionDTO.class,
user1.user.getUuid());
assertEquals(HttpStatus.OK, connectionResponse.getStatusCode());
assertEquals(user2.user.getUuid(), connectionResponse.getBody().getInvitee().getUuid());
assertTrue(connectionResponse.getBody().isConfirmed());
String user1Data = user1Expectation.waitForResponse();
String user2Data = user2Expectation.waitForResponse();
assertEquals(user1Data, user2Data);
assertTrue("All server expectations must be met at the end of a test", server.allExpectationsMet());
assertFalse("Server received a request before ", server.unexpectedQueryReceived());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment