Created
February 6, 2015 18:30
-
-
Save mressler/2802b547ef6feac6c8ad to your computer and use it in GitHub Desktop.
HttpTestServer Additions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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