org.pentaho.di.trans.steps.httppost.HTTPPOSTIT.java Source code

Java tutorial

Introduction

Here is the source code for org.pentaho.di.trans.steps.httppost.HTTPPOSTIT.java

Source

/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

package org.pentaho.di.trans.steps.httppost;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.URLDecoder;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.pentaho.di.core.KettleClientEnvironment;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.core.logging.LoggingObjectInterface;
import org.pentaho.di.core.row.RowMeta;
import org.pentaho.di.core.row.RowMetaInterface;
import org.pentaho.di.core.row.value.ValueMetaInteger;
import org.pentaho.di.core.row.value.ValueMetaString;
import org.pentaho.di.core.util.Assert;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepMeta;
import org.pentaho.di.trans.steps.mock.StepMockHelper;

import com.google.common.io.ByteStreams;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

/**
 * User: Dzmitry Stsiapanau Date: 12/2/13 Time: 4:35 PM
 */
public class HTTPPOSTIT {
    class HTTPPOSTHandler extends HTTPPOST {

        Object[] row = new Object[] { "anyData" };
        Object[] outputRow;
        boolean override;

        public HTTPPOSTHandler(StepMeta stepMeta, StepDataInterface stepDataInterface, int copyNr,
                TransMeta transMeta, Trans trans, boolean override) {
            super(stepMeta, stepDataInterface, copyNr, transMeta, trans);
            this.override = override;
        }

        /**
         * In case of getRow, we receive data from previous steps through the input rowset. In case we split the stream, we
         * have to copy the data to the alternate splits: rowsets 1 through n.
         */
        @Override
        public Object[] getRow() throws KettleException {
            return row;
        }

        /**
         * putRow is used to copy a row, to the alternate rowset(s) This should get priority over everything else!
         * (synchronized) If distribute is true, a row is copied only once to the output rowsets, otherwise copies are sent
         * to each rowset!
         *
         * @param row
         *        The row to put to the destination rowset(s).
         * @throws org.pentaho.di.core.exception.KettleStepException
         *
         */
        @Override
        public void putRow(RowMetaInterface rowMeta, Object[] row) throws KettleStepException {
            outputRow = row;
        }

        public Object[] getOutputRow() {
            return outputRow;
        }

        @Override
        protected int requestStatusCode(PostMethod post, HostConfiguration hostConfiguration,
                HttpClient httpPostClient) throws IOException {
            if (override) {
                return 402;
            } else {
                return super.requestStatusCode(post, hostConfiguration, httpPostClient);
            }

        }

        @Override
        protected InputStreamReader openStream(String encoding, PostMethod post) throws Exception {
            if (override) {
                InputStreamReader mockInputStreamReader = Mockito.mock(InputStreamReader.class);
                when(mockInputStreamReader.read()).thenReturn(-1);
                return mockInputStreamReader;
            } else {
                return super.openStream(encoding, post);
            }
        }

        @Override
        protected Header[] searchForHeaders(PostMethod post) {
            Header[] headers = { new Header("host", host) };
            if (override) {
                return headers;
            } else {
                return super.searchForHeaders(post);
            }
        }
    }

    public static final String host = "localhost";
    public static final int port = 9998;
    public static final String HTTP_LOCALHOST_9998 = "http://localhost:9998/";

    @InjectMocks
    private StepMockHelper<HTTPPOSTMeta, HTTPPOSTData> stepMockHelper;
    private HttpServer httpServer;

    @BeforeClass
    public static void setupBeforeClass() throws KettleException {
        KettleClientEnvironment.init();
    }

    @Before
    public void setUp() throws Exception {
        stepMockHelper = new StepMockHelper<HTTPPOSTMeta, HTTPPOSTData>("HTTPPOST CLIENT TEST", HTTPPOSTMeta.class,
                HTTPPOSTData.class);
        when(stepMockHelper.logChannelInterfaceFactory.create(any(), any(LoggingObjectInterface.class)))
                .thenReturn(stepMockHelper.logChannelInterface);
        when(stepMockHelper.trans.isRunning()).thenReturn(true);
        verify(stepMockHelper.trans, never()).stopAll();
    }

    @After
    public void tearDown() throws Exception {
        httpServer.stop(5);

    }

    @Test
    public void test204Answer() throws Exception {
        startHttpServer(get204AnswerHandler());
        HTTPPOSTData data = new HTTPPOSTData();
        int[] index = { 0, 1 };
        RowMeta meta = new RowMeta();
        meta.addValueMeta(new ValueMetaString("fieldName"));
        meta.addValueMeta(new ValueMetaInteger("codeFieldName"));
        Object[] expectedRow = new Object[] { "", 204L };
        HTTPPOST HTTPPOST = new HTTPPOSTHandler(stepMockHelper.stepMeta, data, 0, stepMockHelper.transMeta,
                stepMockHelper.trans, false);
        RowMetaInterface inputRowMeta = mock(RowMetaInterface.class);
        HTTPPOST.setInputRowMeta(inputRowMeta);
        when(inputRowMeta.clone()).thenReturn(inputRowMeta);
        when(stepMockHelper.processRowsStepMetaInterface.getUrl()).thenReturn(HTTP_LOCALHOST_9998);
        when(stepMockHelper.processRowsStepMetaInterface.getQueryField()).thenReturn(new String[] {});
        when(stepMockHelper.processRowsStepMetaInterface.getArgumentField()).thenReturn(new String[] {});
        when(stepMockHelper.processRowsStepMetaInterface.getResultCodeFieldName())
                .thenReturn("ResultCodeFieldName");
        when(stepMockHelper.processRowsStepMetaInterface.getFieldName()).thenReturn("ResultFieldName");
        HTTPPOST.init(stepMockHelper.processRowsStepMetaInterface, data);
        Assert.assertTrue(HTTPPOST.processRow(stepMockHelper.processRowsStepMetaInterface, data));
        Object[] out = ((HTTPPOSTHandler) HTTPPOST).getOutputRow();
        Assert.assertTrue(meta.equals(out, expectedRow, index));
    }

    @Test
    public void testResponseHeader() throws Exception {
        startHttpServer(get204AnswerHandler());
        HTTPPOSTData data = new HTTPPOSTData();
        int[] index = { 0, 1, 3 };
        RowMeta meta = new RowMeta();
        meta.addValueMeta(new ValueMetaString("fieldName"));
        meta.addValueMeta(new ValueMetaInteger("codeFieldName"));
        meta.addValueMeta(new ValueMetaInteger("responseTimeFieldName"));
        meta.addValueMeta(new ValueMetaString("headerFieldName"));
        Object[] expectedRow = new Object[] { "", 402L, 0L, "{\"host\":\"localhost\"}" };
        HTTPPOST HTTPPOST = new HTTPPOSTHandler(stepMockHelper.stepMeta, data, 0, stepMockHelper.transMeta,
                stepMockHelper.trans, true);
        RowMetaInterface inputRowMeta = mock(RowMetaInterface.class);
        HTTPPOST.setInputRowMeta(inputRowMeta);
        when(inputRowMeta.clone()).thenReturn(inputRowMeta);
        when(stepMockHelper.processRowsStepMetaInterface.getUrl()).thenReturn(HTTP_LOCALHOST_9998);
        when(stepMockHelper.processRowsStepMetaInterface.getQueryField()).thenReturn(new String[] {});
        when(stepMockHelper.processRowsStepMetaInterface.getArgumentField()).thenReturn(new String[] {});
        when(stepMockHelper.processRowsStepMetaInterface.getResultCodeFieldName())
                .thenReturn("ResultCodeFieldName");
        when(stepMockHelper.processRowsStepMetaInterface.getFieldName()).thenReturn("ResultFieldName");
        when(stepMockHelper.processRowsStepMetaInterface.getEncoding()).thenReturn("UTF-8");
        when(stepMockHelper.processRowsStepMetaInterface.getResponseTimeFieldName())
                .thenReturn("ResponseTimeFieldName");
        when(stepMockHelper.processRowsStepMetaInterface.getResponseHeaderFieldName())
                .thenReturn("ResponseHeaderFieldName");
        HTTPPOST.init(stepMockHelper.processRowsStepMetaInterface, data);
        Assert.assertTrue(HTTPPOST.processRow(stepMockHelper.processRowsStepMetaInterface, data));
        Object[] out = ((HTTPPOSTHandler) HTTPPOST).getOutputRow();
        Assert.assertTrue(meta.equals(out, expectedRow, index));
    }

    @Test
    public void testDuplicateNamesInHeader() throws Exception {
        startHttpServer(getDuplicateHeadersHandler());
        HTTPPOSTData data = new HTTPPOSTData();
        RowMeta meta = new RowMeta();
        meta.addValueMeta(new ValueMetaString("headerFieldName"));
        HTTPPOST HTTPPOST = new HTTPPOSTHandler(stepMockHelper.stepMeta, data, 0, stepMockHelper.transMeta,
                stepMockHelper.trans, false);
        RowMetaInterface inputRowMeta = mock(RowMetaInterface.class);
        HTTPPOST.setInputRowMeta(inputRowMeta);
        when(inputRowMeta.clone()).thenReturn(inputRowMeta);
        when(stepMockHelper.processRowsStepMetaInterface.getUrl()).thenReturn(HTTP_LOCALHOST_9998);
        when(stepMockHelper.processRowsStepMetaInterface.getQueryField()).thenReturn(new String[] {});
        when(stepMockHelper.processRowsStepMetaInterface.getArgumentField()).thenReturn(new String[] {});
        when(stepMockHelper.processRowsStepMetaInterface.getEncoding()).thenReturn("UTF-8");
        when(stepMockHelper.processRowsStepMetaInterface.getResponseHeaderFieldName())
                .thenReturn("ResponseHeaderFieldName");
        HTTPPOST.init(stepMockHelper.processRowsStepMetaInterface, data);
        Assert.assertTrue(HTTPPOST.processRow(stepMockHelper.processRowsStepMetaInterface, data));
        Object[] out = ((HTTPPOSTHandler) HTTPPOST).getOutputRow();
        Assert.assertTrue(out.length == 1);
        JSONParser parser = new JSONParser();
        JSONObject json = (JSONObject) parser.parse((String) out[0]);
        Object userAgent = json.get("User-agent");
        Assert.assertTrue("HTTPTool/1.0".equals(userAgent));
        Object cookies = json.get("Set-cookie");
        Assert.assertTrue(cookies instanceof JSONArray);
        for (int i = 0; i < 3; i++) {
            String cookie = ((String) ((JSONArray) cookies).get(i));
            Assert.assertTrue(cookie.startsWith("cookie" + i));
        }
    }

    @Test
    public void testUTF8() throws Exception {
        testServerReturnsCorrectlyEncodedParams("test string \uD842\uDFB7  ", "UTF-8");
    }

    @Test
    public void testUTF16() throws Exception {
        testServerReturnsCorrectlyEncodedParams("test string \uD842\uDFB7  ", "UTF-16");
    }

    @Test
    public void testUTF32() throws Exception {
        testServerReturnsCorrectlyEncodedParams("test string \uD842\uDFB7  ", "UTF-32");
    }

    public void testServerReturnsCorrectlyEncodedParams(String testString, String testCharset) throws Exception {
        AtomicBoolean testStatus = new AtomicBoolean();
        startHttpServer(getEncodingCheckingHandler(testString, testCharset, testStatus));
        HTTPPOSTData data = new HTTPPOSTData();
        RowMeta meta = new RowMeta();
        meta.addValueMeta(new ValueMetaString("fieldName"));
        HTTPPOSTHandler httpPost = new HTTPPOSTHandler(stepMockHelper.stepMeta, data, 0, stepMockHelper.transMeta,
                stepMockHelper.trans, false);
        RowMetaInterface inputRowMeta = mock(RowMetaInterface.class);
        httpPost.setInputRowMeta(inputRowMeta);
        httpPost.row = new Object[] { testString };
        when(inputRowMeta.clone()).thenReturn(inputRowMeta);
        when(inputRowMeta.getString(httpPost.row, 0)).thenReturn(testString);
        when(stepMockHelper.processRowsStepMetaInterface.getUrl()).thenReturn(HTTP_LOCALHOST_9998);
        when(stepMockHelper.processRowsStepMetaInterface.getQueryField()).thenReturn(new String[] {});
        when(stepMockHelper.processRowsStepMetaInterface.getArgumentField())
                .thenReturn(new String[] { "testBodyField" });
        when(stepMockHelper.processRowsStepMetaInterface.getArgumentParameter())
                .thenReturn(new String[] { "testBodyParam" });
        when(stepMockHelper.processRowsStepMetaInterface.getArgumentHeader()).thenReturn(new boolean[] { false });
        when(stepMockHelper.processRowsStepMetaInterface.getFieldName()).thenReturn("ResultFieldName");
        when(stepMockHelper.processRowsStepMetaInterface.getEncoding()).thenReturn(testCharset);
        httpPost.init(stepMockHelper.processRowsStepMetaInterface, data);
        Assert.assertTrue(httpPost.processRow(stepMockHelper.processRowsStepMetaInterface, data));
        Assert.assertTrue(testStatus.get(), "Test failed");
    }

    private void startHttpServer(HttpHandler httpHandler) throws IOException {
        httpServer = HttpServer.create(new InetSocketAddress(HTTPPOSTIT.host, HTTPPOSTIT.port), 10);
        httpServer.createContext("/", httpHandler);
        httpServer.start();
    }

    private HttpHandler get204AnswerHandler() {
        return httpExchange -> {
            httpExchange.sendResponseHeaders(204, 0);
            httpExchange.close();
        };
    }

    private HttpHandler getDuplicateHeadersHandler() {
        return httpExchange -> {
            Headers headers = httpExchange.getResponseHeaders();
            headers.add("User-agent", "HTTPTool/1.0");
            headers.add("Set-cookie", "cookie0=value0; Max-Age=3600");
            headers.add("Set-cookie", "cookie1=value1; HttpOnly");
            headers.add("Set-cookie", "cookie2=value2; Secure");
            httpExchange.sendResponseHeaders(200, 0);
            httpExchange.close();
        };
    }

    private HttpHandler getEncodingCheckingHandler(String expectedResultString, String expectedEncoding,
            AtomicBoolean testStatus) {
        return httpExchange -> {
            try {
                checkEncoding(expectedResultString, expectedEncoding, httpExchange.getRequestBody());
                testStatus.set(true);
            } catch (Throwable e) {
                e.printStackTrace();
                testStatus.set(false);
            } finally {
                httpExchange.sendResponseHeaders(200, 0);
                httpExchange.close();
            }
        };
    }

    private void checkEncoding(String expectedResult, String encoding, InputStream inputStream) throws Exception {
        byte[] receivedBytes = ByteStreams.toByteArray(inputStream);
        String urlEncodedString = new String(receivedBytes, "US-ASCII");
        String finalString = URLDecoder.decode(urlEncodedString, encoding);
        expectedResult = "testBodyParam=" + expectedResult;
        assertEquals("The final received string is not the same", expectedResult, finalString);
    }

}