package com.softwaremill.common.testserver; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.BasicHttpEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @Test(singleThreaded = true) public class TestServerTest { @Test public void shouldStoreRequest() throws Exception { // Given TestServer server = new TestServer(); server.start(); try { LogAndStoreRequestResponder responder = new LogAndStoreRequestResponder(); server.addResponder(responder); // When HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet("http://localhost:18182/path?param1=value1¶m2=2"); get.addHeader("Custom-Header", "CustomValue"); HttpResponse response = client.execute(get); // Then assertResponseOk(response); List<LogAndStoreRequestResponder.RequestInfo> requestsReceived = responder.getRequestsReceived(); assertThat(requestsReceived).hasSize(1); LogAndStoreRequestResponder.RequestInfo request = requestsReceived.get(0); assertThat(request.getMethod()).isEqualTo("GET"); assertThat(request.getPath()).isEqualTo("/path"); assertThat(request.getParameters()).hasSize(2); assertThat(request.getParameters().get("param1")).hasSize(1); assertThat(request.getParameters().get("param1")[0]).isEqualTo("value1"); assertThat(request.getParameters().get("param2")).hasSize(1); assertThat(request.getParameters().get("param2")[0]).isEqualTo("2"); assertThat(request.getHeaders().size()).isGreaterThanOrEqualTo(1); assertThat(request.getHeaders().get("Custom-Header")).hasSize(1); assertThat(request.getHeaders().get("Custom-Header")[0]).isEqualTo("CustomValue"); } finally { server.stop(); } } @Test public void shouldStorePostRequest() throws Exception { // Given TestServer server = new TestServer(); server.start(); try { LogAndStoreRequestResponder responder = new LogAndStoreRequestResponder(); server.addResponder(responder); // When HttpClient client = new DefaultHttpClient(); HttpPost post = new HttpPost("http://localhost:18182/path?param1=value1¶m2=2"); post.addHeader("Custom-Header", "CustomValue"); BasicHttpEntity entity = new BasicHttpEntity(); entity.setContent(IOUtils.toInputStream("some content sent in POST")); post.setEntity(entity); HttpResponse response = client.execute(post); // Then assertResponseOk(response); List<LogAndStoreRequestResponder.RequestInfo> requestsReceived = responder.getRequestsReceived(); assertThat(requestsReceived).hasSize(1); LogAndStoreRequestResponder.RequestInfo request = requestsReceived.get(0); assertThat(request.getMethod()).isEqualTo("POST"); assertThat(request.getPath()).isEqualTo("/path"); assertThat(request.getParameters()).hasSize(2); assertThat(request.getParameters().get("param1")).hasSize(1); assertThat(request.getParameters().get("param1")[0]).isEqualTo("value1"); assertThat(request.getParameters().get("param2")).hasSize(1); assertThat(request.getParameters().get("param2")[0]).isEqualTo("2"); assertThat(request.getHeaders().size()).isGreaterThanOrEqualTo(1); assertThat(request.getHeaders().get("Custom-Header")).hasSize(1); assertThat(request.getHeaders().get("Custom-Header")[0]).isEqualTo("CustomValue"); assertThat(request.getContent()).isEqualTo("some content sent in POST"); } finally { server.stop(); } } @Test public void shouldAcceptHttpsConnections() throws Exception { // Given TestServer server = new TestServer(); addResponderAndStartServer(server); try { // When HttpResponse response = gulliblyCallHttps("https://localhost:18183", 18183); // Then assertResponseOk(response); } finally { server.stop(); } } @Test public void shouldRunOnSpecifiedPort() throws Exception { // Given TestServer server = new TestServer(8765); addResponderAndStartServer(server); try { // When HttpResponse response = callUrl("http://localhost:8765"); // Then assertResponseOk(response); } finally { server.stop(); } } @Test public void shouldRunHttpsOnSpecifiedPort() throws Exception { // Given TestServer server = new TestServer(8765, 8766); addResponderAndStartServer(server); try { // When HttpResponse response = gulliblyCallHttps("https://localhost:8766", 8766); // Then assertResponseOk(response); } finally { server.stop(); } } @Test public void shouldNotAllowUnauthenticatedUserOnSecuredPath() throws Exception { // Given TestServer server = new TestServer(); addResponderAndStartServer(server); server.secure("/secure", "user", "pass"); try { // When HttpResponse response = callUrl("http://localhost:18182/secure"); // Then assertThat(response.getStatusLine().getStatusCode()).isEqualTo(401); } finally { server.stop(); } } @Test public void shouldAllowAuthenticatedUserOnSecuredPath() throws Exception { // Given TestServer server = new TestServer(); addResponderAndStartServer(server); server.secure("/secure", "user", "pass"); try { // When DefaultHttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet("http://localhost:18182/secure"); client.getCredentialsProvider().setCredentials( new AuthScope("localhost", 18182), new UsernamePasswordCredentials("user", "pass")); HttpResponse response = client.execute(get); // Then assertResponseOk(response); } finally { server.stop(); } } @Test public void shouldAllowUnauthenticatedUserOnPublicPath() throws Exception { // Given TestServer server = new TestServer(); addResponderAndStartServer(server); server.secure("/secure", "user", "pass"); try { // When DefaultHttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet("http://localhost:18182/public"); client.getCredentialsProvider().setCredentials( new AuthScope("localhost", 18182), new UsernamePasswordCredentials("user", "pass")); HttpResponse response = client.execute(get); // Then assertResponseOk(response); } finally { server.stop(); } } @Test(dataProvider = "orderedResponders") public void shouldRunRespondersInOrderTheyWereAdded(TestServer serverWithResponders, String expectedContent) throws Exception { // Given serverWithResponders.start(); try { // When HttpResponse response = callUrl("http://localhost:18182"); String content = IOUtils.toString(response.getEntity().getContent()); // Then assertThat(content).isEqualTo(expectedContent); } finally { serverWithResponders.stop(); } } @Test public void shouldClearResponders() throws Exception { // Given TestServer server = new TestServer(); server.addResponder(new LogAndStoreRequestResponder()); server.start(); try { // When server.clearResponders(); // Then HttpResponse response = callUrl("http://localhost:18182"); assertThat(response.getStatusLine().getStatusCode()).isEqualTo(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); String content = IOUtils.toString(response.getEntity().getContent()); assertThat(content).isEqualTo("No responder could handle this request"); } finally { server.stop(); } } @DataProvider public Object[][] orderedResponders() { TestServer serverMaryFirst = new TestServer(); serverMaryFirst.addResponder(new MaryResponder()); serverMaryFirst.addResponder(new JohnResponder()); TestServer serverJohnFirst = new TestServer(); serverJohnFirst.addResponder(new JohnResponder()); serverJohnFirst.addResponder(new MaryResponder()); return new Object[][]{ { serverMaryFirst, "Mary" }, { serverJohnFirst, "John" }, }; } private HttpResponse callUrl(String url) throws IOException { HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(url); return client.execute(get); } private HttpResponse gulliblyCallHttps(String url, int port) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, IOException { HttpClient client = createGullibleHttpClient(port); HttpGet get = new HttpGet(url); return client.execute(get); } private void assertResponseOk(HttpResponse response) throws IOException { assertThat(response.getStatusLine().getStatusCode()).isEqualTo(200); assertThat(IOUtils.toString(response.getEntity().getContent())).isEqualTo("OK"); } private void addResponderAndStartServer(TestServer server) throws Exception { server.addResponder(new LogAndStoreRequestResponder()); server.start(); } private HttpClient createGullibleHttpClient(int sslPort) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException { SchemeRegistry registry = createTrustEveryoneRegistry(sslPort); ThreadSafeClientConnManager connectionManager = new ThreadSafeClientConnManager(registry); return new DefaultHttpClient(connectionManager); } private SchemeRegistry createTrustEveryoneRegistry(int sslPort) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { TrustStrategy easyStrategy = new TrustStrategy() { @Override public boolean isTrusted(X509Certificate[] certificate, String authType) throws CertificateException { return true; } }; SSLSocketFactory sf = new SSLSocketFactory(easyStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("https", sslPort, sf)); return registry; } private class MaryResponder implements Responder { @Override public boolean canRespond(HttpServletRequest request) { return true; } @Override public void respond(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/plain"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().print("Mary"); response.getWriter().close(); } } private class JohnResponder implements Responder { @Override public boolean canRespond(HttpServletRequest request) { return true; } @Override public void respond(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType("text/plain"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().print("John"); response.getWriter().close(); } } }