package org.mockserver.integration.proxy; import com.google.common.base.Charsets; import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.DefaultProxyRoutePlanner; import org.apache.http.message.BasicHeader; import org.apache.http.util.EntityUtils; import org.junit.Test; import org.mockserver.client.proxy.ProxyClient; import org.mockserver.model.HttpStatusCode; import org.mockserver.socket.SSLFactory; import org.mockserver.streams.IOStreamUtils; import java.io.OutputStream; import java.net.Socket; import static org.hamcrest.Matchers.is; import static org.hamcrest.core.StringStartsWith.startsWith; import static org.junit.Assert.*; import static org.mockserver.model.HttpRequest.request; import static org.mockserver.test.Assert.assertContains; import static org.mockserver.verify.VerificationTimes.atLeast; import static org.mockserver.verify.VerificationTimes.exactly; /** * @author jamesdbloom */ public abstract class AbstractClientProxyIntegrationTest { protected static String servletContext = ""; protected HttpClient createHttpClient() throws Exception { return HttpClients .custom() .setSSLSocketFactory(new SSLConnectionSocketFactory(SSLFactory.getInstance().sslContext(), NoopHostnameVerifier.INSTANCE)) .setRoutePlanner(new DefaultProxyRoutePlanner( new HttpHost( System.getProperty("http.proxyHost", "localhost"), Integer.parseInt(System.getProperty("http.proxyPort", String.valueOf(getProxyPort()))) ) )).build(); } public abstract int getProxyPort(); public abstract ProxyClient getProxyClient(); public abstract int getServerPort(); protected String calculatePath(String path) { return ("/" + servletContext + "/" + path).replaceAll("//", "/"); } @Test public void shouldForwardRequestsUsingSocketDirectly() throws Exception { Socket socket = null; try { socket = new Socket("localhost", getProxyPort()); // given OutputStream output = socket.getOutputStream(); // when // - send GET request for headers only output.write(("" + "GET " + calculatePath("test_headers_only") + " HTTP/1.1\r\n" + "Host: localhost:" + getServerPort() + "\r\n" + "x-test: test_headers_only\r\n" + "Connection: keep-alive\r\n" + "\r\n" ).getBytes(Charsets.UTF_8)); output.flush(); // then assertContains(IOStreamUtils.readInputStreamToString(socket), "x-test: test_headers_only"); // and getProxyClient().verify( request() .withMethod("GET") .withPath("/test_headers_only"), exactly(1) ); // - send GET request for headers and body output.write(("" + "GET " + calculatePath("test_headers_and_body") + " HTTP/1.1\r\n" + "Host: localhost:" + getServerPort() + "\r\n" + "Content-Length: " + "an_example_body".getBytes(Charsets.UTF_8).length + "\r\n" + "x-test: test_headers_and_body\r\n" + "\r\n" + "an_example_body" ).getBytes(Charsets.UTF_8)); output.flush(); // then String response = IOStreamUtils.readInputStreamToString(socket); assertContains(response, "x-test: test_headers_and_body"); assertContains(response, "an_example_body"); // and getProxyClient().verify( request() .withMethod("GET") .withPath("/test_headers_and_body") .withBody("an_example_body"), exactly(1) ); } finally { if (socket != null) { socket.close(); } } } @Test public void shouldForwardRequestsUsingHttpClient() throws Exception { // given HttpClient httpClient = createHttpClient(); // when HttpPost request = new HttpPost( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ); request.setEntity(new StringEntity("an_example_body")); HttpResponse response = httpClient.execute(request); // then assertEquals(HttpStatusCode.OK_200.code(), response.getStatusLine().getStatusCode()); assertEquals("an_example_body", new String(EntityUtils.toByteArray(response.getEntity()), com.google.common.base.Charsets.UTF_8)); // and getProxyClient().verify( request() .withMethod("POST") .withPath("/test_headers_and_body") .withBody("an_example_body"), exactly(1) ); } @Test public void shouldForwardRequestsWithComplexCookies() throws Exception { // given HttpClient httpClient = createHttpClient(); Header setCookieOneHeader = new BasicHeader("Set-Cookie", "personalization_59996b985e24ce008d3df3bd07e27c1b=\"\"; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/"); Header setCookieTwoHeader = new BasicHeader("Set-Cookie", "anonymous_59996b985e24ce008d3df3bd07e27c1b=acgzEaAKOVR=mAY9yJhP7IrC9Am; Version=1; Comment=\"Anonymous cookie for site\"; Max-Age=15552000; Expires=Sat, 19-Mar-2016 18:43:26 GMT; Path=/"); Header cookieOneHeader = new BasicHeader("Cookie", "personalization_59996b985e24ce008d3df3bd07e27c1b=\"\""); Header cookieTwoHeader = new BasicHeader("Cookie", "anonymous_59996b985e24ce008d3df3bd07e27c1b=\"acgzEaAKOVR=mAY9yJhP7IrC9Am\""); // when HttpPost request = new HttpPost( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ); request.addHeader(setCookieOneHeader); request.addHeader(setCookieTwoHeader); request.addHeader(cookieOneHeader); request.addHeader(cookieTwoHeader); request.setEntity(new StringEntity("an_example_body")); HttpResponse response = httpClient.execute(request); // then assertEquals(HttpStatusCode.OK_200.code(), response.getStatusLine().getStatusCode()); assertThat(response.getHeaders("Set-Cookie").length, is(2)); assertThat(response.getHeaders("Set-Cookie")[0].getValue(), is(setCookieOneHeader.getValue())); assertThat(response.getHeaders("Set-Cookie")[1].getValue(), is(setCookieTwoHeader.getValue())); assertEquals("an_example_body", new String(EntityUtils.toByteArray(response.getEntity()), com.google.common.base.Charsets.UTF_8)); // and getProxyClient().verify( request() .withMethod("POST") .withPath("/test_headers_and_body") .withHeader(setCookieOneHeader.getName(), setCookieOneHeader.getValue()) .withHeader(setCookieTwoHeader.getName(), setCookieTwoHeader.getValue()) .withCookie("personalization_59996b985e24ce008d3df3bd07e27c1b", "") .withCookie("anonymous_59996b985e24ce008d3df3bd07e27c1b", "acgzEaAKOVR=mAY9yJhP7IrC9Am") .withBody("an_example_body"), exactly(1) ); } @Test public void shouldForwardRequestsToUnknownPath() throws Exception { Socket socket = null; try { socket = new Socket("localhost", getProxyPort()); // given OutputStream output = socket.getOutputStream(); // when // - send GET request output.write(("" + "GET " + calculatePath("not_found") + " HTTP/1.1\r\n" + "Host: localhost:" + getServerPort() + "\r\n" + "Connection: close\r\n" + "\r\n" ).getBytes(Charsets.UTF_8)); output.flush(); // then assertContains(IOStreamUtils.readInputStreamToString(socket), "HTTP/1.1 404 Not Found"); // and getProxyClient().verify( request() .withMethod("GET") .withPath("/not_found"), exactly(1) ); } finally { if (socket != null) { socket.close(); } } } @Test public void shouldVerifyRequests() throws Exception { // given HttpClient httpClient = createHttpClient(); // when httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_only")) .build() ) ); // then getProxyClient() .verify( request() .withMethod("GET") .withPath("/test_headers_and_body") ); getProxyClient() .verify( request() .withMethod("GET") .withPath("/test_headers_and_body"), exactly(1) ); getProxyClient() .verify( request() .withPath("/test_headers_.*"), atLeast(1) ); getProxyClient() .verify( request() .withPath("/test_headers_.*"), exactly(2) ); getProxyClient() .verify( request() .withPath("/other_path"), exactly(0) ); } @Test public void shouldVerifyZeroRequests() throws Exception { // given HttpClient httpClient = createHttpClient(); // when httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); // then try { getProxyClient() .verify( request() .withPath("/test_headers_and_body"), exactly(0) ); fail(); } catch (AssertionError ae) { assertThat(ae.getMessage(), startsWith("Request not found exactly 0 times, expected:<{" + System.getProperty("line.separator") + " \"path\" : \"" + "/test_headers_and_body" + "\"" + System.getProperty("line.separator") + "}> but was:<{" + System.getProperty("line.separator") + " \"method\" : \"GET\"," + System.getProperty("line.separator") + " \"path\" : \"" + "/test_headers_and_body" + "\"," + System.getProperty("line.separator"))); } } @Test public void shouldVerifyNoRequestsExactly() throws Exception { // given HttpClient httpClient = createHttpClient(); // when httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); // then try { getProxyClient() .verify( request() .withPath("/other_path"), exactly(1) ); fail(); } catch (AssertionError ae) { assertThat(ae.getMessage(), startsWith("Request not found exactly once, expected:<{" + System.getProperty("line.separator") + " \"path\" : \"" + "/other_path" + "\"" + System.getProperty("line.separator") + "}> but was:<{" + System.getProperty("line.separator") + " \"method\" : \"GET\"," + System.getProperty("line.separator") + " \"path\" : \"" + "/test_headers_and_body" + "\"," + System.getProperty("line.separator"))); } } @Test public void shouldVerifyNoRequestsTimesNotSpecified() throws Exception { // given HttpClient httpClient = createHttpClient(); // when httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); // then try { getProxyClient() .verify( request() .withPath("/other_path") ); fail(); } catch (AssertionError ae) { assertThat(ae.getMessage(), startsWith("Request sequence not found, expected:<[ {" + System.getProperty("line.separator") + " \"path\" : \"" + "/other_path" + "\"" + System.getProperty("line.separator") + "} ]> but was:<[ {" + System.getProperty("line.separator") + " \"method\" : \"GET\"," + System.getProperty("line.separator") + " \"path\" : \"" + "/test_headers_and_body" + "\"," + System.getProperty("line.separator"))); } } @Test public void shouldVerifyNotEnoughRequests() throws Exception { // given HttpClient httpClient = createHttpClient(); // when httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); // then try { getProxyClient() .verify( request() .withPath("/test_headers_and_body"), atLeast(3) ); fail(); } catch (AssertionError ae) { assertThat(ae.getMessage(), startsWith("Request not found at least 3 times, expected:<{" + System.getProperty("line.separator") + " \"path\" : \"" + "/test_headers_and_body" + "\"" + System.getProperty("line.separator") + "}> but was:<[ {" + System.getProperty("line.separator") + " \"method\" : \"GET\"," + System.getProperty("line.separator") + " \"path\" : \"" + "/test_headers_and_body" + "\"," + System.getProperty("line.separator"))); } } @Test public void shouldClearRequests() throws Exception { // given HttpClient httpClient = createHttpClient(); // when httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_only")) .build() ) ); getProxyClient() .clear( request() .withMethod("GET") .withPath("/test_headers_and_body") ); // then getProxyClient() .verify( request() .withMethod("GET") .withPath("/test_headers_and_body"), exactly(0) ); getProxyClient() .verify( request() .withPath("/test_headers_.*"), exactly(1) ); } @Test public void shouldResetRequests() throws Exception { // given HttpClient httpClient = createHttpClient(); // when httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_and_body")) .build() ) ); httpClient.execute( new HttpGet( new URIBuilder() .setScheme("http") .setHost("localhost") .setPort(getServerPort()) .setPath(calculatePath("test_headers_only")) .build() ) ); getProxyClient().reset(); // then getProxyClient() .verify( request() .withMethod("GET") .withPath("/test_headers_and_body"), exactly(0) ); getProxyClient() .verify( request() .withPath("/test_headers_.*"), atLeast(0) ); getProxyClient() .verify( request() .withPath("/test_headers_.*"), exactly(0) ); } }