org.mule.module.http.functional.proxy.HttpProxyTemplateTestCase.java Source code

Java tutorial

Introduction

Here is the source code for org.mule.module.http.functional.proxy.HttpProxyTemplateTestCase.java

Source

/*
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.module.http.functional.proxy;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
import static org.mule.module.http.api.HttpHeaders.Names.X_FORWARDED_FOR;
import org.mule.api.config.MuleProperties;
import org.mule.config.spring.util.ProcessingStrategyUtils;
import org.mule.module.http.api.HttpHeaders;
import org.mule.module.http.functional.TestInputStream;
import org.mule.module.http.functional.requester.AbstractHttpRequestTestCase;
import org.mule.tck.SensingNullRequestResponseMessageProcessor;
import org.mule.tck.junit4.rule.DynamicPort;
import org.mule.tck.junit4.rule.SystemProperty;
import org.mule.util.IOUtils;
import org.mule.util.concurrent.Latch;

import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.ListenableFuture;
import com.ning.http.client.generators.InputStreamBodyGenerator;
import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.fluent.Response;
import org.apache.http.entity.ContentType;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class HttpProxyTemplateTestCase extends AbstractHttpRequestTestCase {

    @Rule
    public DynamicPort proxyPort = new DynamicPort("proxyPort");

    @Rule
    public SystemProperty systemProperty;

    private static String SENSING_REQUEST_RESPONSE_PROCESSOR_NAME = "sensingRequestResponseProcessor";
    private RequestHandlerExtender handlerExtender;
    private boolean consumeAllRequest = true;
    private String configFile;
    private String requestThreadNameSubString;
    private String responeThreadNameSubString;
    private boolean nonBlocking;

    @Parameterized.Parameters
    public static Collection<Object[]> parameters() {
        return Arrays.asList(new Object[][] { { "http-proxy-template-config.xml", "worker", "worker", false },
                { "http-proxy-template-config.xml", "worker", "proxyTemplate", true } });
    }

    public HttpProxyTemplateTestCase(String configFile, String requestThreadNameSubString,
            String responeThreadNameSubString, boolean nonBlocking) {
        this.configFile = configFile;
        this.requestThreadNameSubString = requestThreadNameSubString;
        this.responeThreadNameSubString = responeThreadNameSubString;
        this.nonBlocking = nonBlocking;
        if (nonBlocking) {
            systemProperty = new SystemProperty(MuleProperties.MULE_DEFAULT_PROCESSING_STRATEGY,
                    ProcessingStrategyUtils.NON_BLOCKING_PROCESSING_STRATEGY);
        }
    }

    @Override
    protected String getConfigFile() {
        return configFile;
    }

    @Test
    public void proxySimpleRequests() throws Exception {
        handlerExtender = null;
        assertRequestOk(getProxyUrl(""), null);
        assertRequestOk(getProxyUrl("test"), null);
    }

    @Test
    public void failIfTargetServiceIsDown() throws Exception {
        handlerExtender = null;
        stopServer();
        Response response = Request.Get(getProxyUrl("")).connectTimeout(RECEIVE_TIMEOUT).execute();
        HttpResponse httpResponse = response.returnResponse();
        assertThat(httpResponse.getStatusLine().getStatusCode(), is(500));
    }

    @Test
    public void proxyMethod() throws Exception {
        handlerExtender = new EchoRequestHandlerExtender() {
            @Override
            protected String selectRequestPartToReturn(org.eclipse.jetty.server.Request baseRequest) {
                return baseRequest.getMethod();
            }
        };
        assertRequestOk(getProxyUrl("test?parameterName=parameterValue"), "GET");

        Response response = Request.Post(getProxyUrl("test?parameterName=parameterValue"))
                .bodyString("Some Text", ContentType.DEFAULT_TEXT).connectTimeout(RECEIVE_TIMEOUT).execute();
        HttpResponse httpResponse = response.returnResponse();
        assertThat(httpResponse.getStatusLine().getStatusCode(), is(200));
        assertThat(IOUtils.toString(httpResponse.getEntity().getContent()), is("POST"));
    }

    @Ignore
    @Test
    public void proxyProtocolHttp1_0() throws Exception {
        handlerExtender = new EchoRequestHandlerExtender() {
            @Override
            protected String selectRequestPartToReturn(org.eclipse.jetty.server.Request baseRequest) {
                return baseRequest.getProtocol();
            }
        };

        Response response = Request.Get(getProxyUrl("test?parameterName=parameterValue"))
                .version(HttpVersion.HTTP_1_0).connectTimeout(RECEIVE_TIMEOUT).execute();
        HttpResponse httpResponse = response.returnResponse();
        assertThat(httpResponse.getStatusLine().getStatusCode(), is(200));
        assertThat(IOUtils.toString(httpResponse.getEntity().getContent()), is("HTTP/1.0"));
    }

    @Test
    public void proxyProtocolHttp1_1() throws Exception {
        handlerExtender = new EchoRequestHandlerExtender() {
            @Override
            protected String selectRequestPartToReturn(org.eclipse.jetty.server.Request baseRequest) {
                return baseRequest.getProtocol();
            }
        };
        assertRequestOk(getProxyUrl("test?parameterName=parameterValue"), "HTTP/1.1");
    }

    @Test
    public void proxyStreaming() throws Exception {
        final Latch latch = new Latch();
        consumeAllRequest = false;
        handlerExtender = new RequestHandlerExtender() {
            @Override
            public void handleRequest(org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request,
                    HttpServletResponse response) throws IOException {
                extractHeadersFromBaseRequest(baseRequest);

                latch.release();
                IOUtils.toString(baseRequest.getInputStream());

                response.setContentType(request.getContentType());
                response.setStatus(HttpServletResponse.SC_OK);
                response.getWriter().print("OK");
            }
        };

        AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder();
        AsyncHttpClientConfig config = configBuilder.build();
        AsyncHttpClient asyncHttpClient = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config);

        AsyncHttpClient.BoundRequestBuilder boundRequestBuilder = asyncHttpClient
                .preparePost(getProxyUrl("test?parameterName=parameterValue"));
        boundRequestBuilder.setBody(new InputStreamBodyGenerator(new TestInputStream(latch)));
        ListenableFuture<com.ning.http.client.Response> future = boundRequestBuilder.execute();

        com.ning.http.client.Response response = future.get();
        assertThat(response.getStatusCode(), is(200));
        response.getHeaders();

        assertThat(getFirstReceivedHeader(HttpHeaders.Names.TRANSFER_ENCODING), is(HttpHeaders.Values.CHUNKED));
        assertThat(response.getResponseBody(), is("OK"));

        asyncHttpClient.close();
    }

    @Test
    public void proxyPath() throws Exception {
        handlerExtender = new EchoRequestHandlerExtender() {
            @Override
            protected String selectRequestPartToReturn(org.eclipse.jetty.server.Request baseRequest) {
                return baseRequest.getPathInfo();
            }
        };
        assertRequestOk(getProxyUrl("test?parameterName=parameterValue"), "/test");
    }

    @Test
    public void proxyQueryString() throws Exception {
        handlerExtender = new EchoRequestHandlerExtender() {
            @Override
            protected String selectRequestPartToReturn(org.eclipse.jetty.server.Request baseRequest) {
                return baseRequest.getQueryString();
            }
        };
        assertRequestOk(getProxyUrl("test?parameterName=parameterValue"), "parameterName=parameterValue");
    }

    @Test
    public void proxyBody() throws Exception {
        handlerExtender = new EchoRequestHandlerExtender() {
            @Override
            protected String selectRequestPartToReturn(org.eclipse.jetty.server.Request baseRequest) {
                return body;
            }
        };

        Response response = Request.Post(getProxyUrl("test")).bodyString("Some Text", ContentType.DEFAULT_TEXT)
                .connectTimeout(RECEIVE_TIMEOUT).execute();
        HttpResponse httpResponse = response.returnResponse();
        assertThat(httpResponse.getStatusLine().getStatusCode(), is(200));
        assertThat(IOUtils.toString(httpResponse.getEntity().getContent()), is("Some Text"));
    }

    @Test
    public void proxyHeaders() throws Exception {
        handlerExtender = null;

        Response response = Request.Get(getProxyUrl("/test?name=value"))
                .addHeader("MyCustomHeaderName", "MyCustomHeaderValue").connectTimeout(RECEIVE_TIMEOUT).execute();
        HttpResponse httpResponse = response.returnResponse();
        assertThat(httpResponse.getStatusLine().getStatusCode(), is(200));

        assertThat(getFirstReceivedHeader("MyCustomHeaderName"), is("MyCustomHeaderValue"));

        Set<String> lowerCaseHeaderNames = new HashSet<>();
        for (Header header : httpResponse.getAllHeaders()) {
            lowerCaseHeaderNames.add(header.getName().toLowerCase());
            // Ensure no synthetic properties in headers
            assertThat(header.getName(), not(startsWith("http.")));
        }

        // Ensure not repeated headers
        assertThat(lowerCaseHeaderNames.size(), is(httpResponse.getAllHeaders().length));
    }

    @Test
    public void setXForwardedForHeader() throws Exception {
        handlerExtender = null;

        Response response = Request.Get(getProxyUrl("")).connectTimeout(RECEIVE_TIMEOUT).execute();
        HttpResponse httpResponse = response.returnResponse();
        assertThat(httpResponse.getStatusLine().getStatusCode(), is(200));

        assertThat(getFirstReceivedHeader(X_FORWARDED_FOR), startsWith("/127.0.0.1:"));
    }

    @Test
    public void requestThread() throws Exception {
        Request.Get(getProxyUrl("")).connectTimeout(RECEIVE_TIMEOUT).execute();
        SensingNullRequestResponseMessageProcessor sensingMessageProcessor = getSensingNullRequestResponseMessageProcessor();
        assertThat(sensingMessageProcessor.requestThread.getName(), containsString(requestThreadNameSubString));
    }

    @Test
    public void responseThread() throws Exception {
        assertRequestOk(getProxyUrl(""), null);
        SensingNullRequestResponseMessageProcessor requestResponseProcessor = getSensingNullRequestResponseMessageProcessor();
        if (nonBlocking) {
            assertThat(requestResponseProcessor.requestThread,
                    not(equalTo(requestResponseProcessor.responseThread)));
            assertThat(requestResponseProcessor.responseThread.getName(),
                    containsString(responeThreadNameSubString));
        } else {
            assertThat(requestResponseProcessor.requestThread, equalTo(requestResponseProcessor.responseThread));
        }
    }

    private SensingNullRequestResponseMessageProcessor getSensingNullRequestResponseMessageProcessor() {
        return muleContext.getRegistry().lookupObject(SENSING_REQUEST_RESPONSE_PROCESSOR_NAME);
    }

    private void assertRequestOk(String url, String expectedResponse) throws IOException {
        Response response = Request.Get(url).connectTimeout(RECEIVE_TIMEOUT).execute();
        HttpResponse httpResponse = response.returnResponse();
        assertThat(httpResponse.getStatusLine().getStatusCode(), is(200));
        if (expectedResponse != null) {
            assertThat(IOUtils.toString(httpResponse.getEntity().getContent()), is(expectedResponse));
        }
    }

    private String getProxyUrl(String path) {
        return String.format("http://localhost:%s/%s", proxyPort.getNumber(), path);
    }

    private String getServerUrl(String path) {
        return String.format("http://localhost:%s/%s", httpPort.getNumber(), path);
    }

    protected void handleRequest(org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        if (consumeAllRequest) {
            extractBaseRequestParts(baseRequest);
        }

        if (handlerExtender == null) {
            writeResponse(response);
        } else {
            handlerExtender.handleRequest(baseRequest, request, response);
        }
    }

    private static interface RequestHandlerExtender {
        void handleRequest(org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request,
                HttpServletResponse response) throws IOException;
    }

    private static abstract class EchoRequestHandlerExtender implements RequestHandlerExtender {
        @Override
        public void handleRequest(org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request,
                HttpServletResponse response) throws IOException {
            response.setContentType(request.getContentType());
            response.setStatus(HttpServletResponse.SC_OK);
            response.getWriter().print(selectRequestPartToReturn(baseRequest));
        }

        protected abstract String selectRequestPartToReturn(org.eclipse.jetty.server.Request baseRequest);
    }

}