org.n52.wps.test.Wps4rIT.java Source code

Java tutorial

Introduction

Here is the source code for org.n52.wps.test.Wps4rIT.java

Source

/**
 * Copyright (C) 2007 - 2014 52North Initiative for Geospatial Open Source
 * Software GmbH
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 *
 * If the program is linked with libraries which are licensed under one of
 * the following licenses, the combination of the program with the linked
 * library is not considered a "derivative work" of the program:
 *
 *        Apache License, version 2.0
 *        Apache Software License, version 1.0
 *        GNU Lesser General Public License, version 3
 *        Mozilla Public License, versions 1.0, 1.1 and 2.0
 *        Common Development and Distribution License (CDDL), version 1.0
 *
 * Therefore the distribution of the program linked with libraries licensed
 * under the aforementioned licenses, is permitted by the copyright holders
 * if the distribution is compliant with both the GNU General Public
 * License version 2 and the aforementioned licenses.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 */

package org.n52.wps.test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;

import java.io.IOException;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Random;
import java.util.UUID;

import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.io.IOUtils;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.rosuda.REngine.Rserve.RConnection;
import org.rosuda.REngine.Rserve.RserveException;
import org.xml.sax.SAXException;

/**
 * 
 * To run this integration tests there has to be RServe running on the localhost and the R repository must be
 * enabled in the WPS config.
 * 
 * To start RServe:
 * 
 * <ul>
 * <li>start <code>R</code></li>
 * <li>in the R console, load the library Rserve: <code>library(Rserve)</code></li>
 * <li>in the R console, start Rserve: <code>Rserve()</code></li>
 * <li>you should see and output "... Ok, ready to answer queries."</li>
 * </ul>
 * 
 * To enable the R process repository:
 * 
 * <ul>
 * <li>open your WPSConfiguration file, normally located in /config/wps_config.xml</li>
 * <li>Find the "LocalRAlgorithmRepository"</li>
 * <li>set the attribute "active" to <code>true</code></li>
 * <li>(restart your WPS server)</li>
 * </ul>
 */
public class Wps4rIT {

    private static String wpsUrl;

    @BeforeClass
    public static void beforeClass() {
        wpsUrl = AllTestsIT.getURL();

        // Seems not to work but it would be nice if it does...
        // URL resource = WPS4RTester.class
        // .getResource("/R/wps_config.xml");
        // WPSConfig.forceInitialization(new File(resource.getFile()).getAbsolutePath());

        String host = System.getProperty("test.rserve.host", "127.0.0.1");
        int port = Integer.parseInt(System.getProperty("test.rserve.port", "6311"));
        String user = System.getProperty("test.rserve.user", null);
        String password = System.getProperty("test.rserve.pwd", null);
        try {
            RConnection c = getNewConnection(host, port, user, password);
            c.close();
        } catch (RserveException e1) {
            Assume.assumeNoException(e1);
        }
    }

    @AfterClass
    public static void afterClass() {
        // WPSConfig.forceInitialization("src/main/webapp/config/wps_config.xml");
    }

    private static RConnection getNewConnection(String host, int port, String user, String password)
            throws RserveException {
        RConnection con = new RConnection(host, port);
        if (con != null && con.needLogin())
            con.login(user, password);

        return con;
    }

    /*
     * DN: test disabled, sessionInfo.jsp was deleted, service endpoint must be implemented.
     */
    // @Test
    public void sessionInfoRetrievedFromWPSWebsite() throws MalformedURLException {
        String temp = wpsUrl.substring(0, wpsUrl.lastIndexOf("/"));
        URL urlSessionInfo = new URL(temp + "/rsessioninfoendpoint");
        try {
            String response = GetClient.sendRequest(urlSessionInfo.toExternalForm());
            assertThat(response, containsString("R ")); // "R version" fails if using unstable R!
            assertThat(response, containsString("Platform:"));
            assertThat(response, containsString("attached base packages:"));
        } catch (IOException e) {
            String message = "Cannot retrieve the R session info from WPS.";
            e.printStackTrace();
            throw new AssertionError(message);
        }
    }

    @Test
    public void resourcesAreLoadedAndRead()
            throws IOException, ParserConfigurationException, SAXException, XmlException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestResources.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        String payload = xmlPayload.toString();
        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
        assertThat("response is not an exception", response, not(containsString("ExceptionReport")));
        assertThat("text resource content could be read", response,
                containsString("dataType=\"xs:string\">This is a dummy txt-file"));
        assertThat("image resource is loaded", response, containsString("480"));
        assertThat("directories are created", response, containsString("xs:integer\">1</wps:LiteralData>"));
        assertThat("subdirectory resources can be read", response,
                containsString("xs:double\">42.0</wps:LiteralData>"));
        assertThat("subsubdirectory resources can be read", response,
                containsString("xs:integer\">17</wps:LiteralData>"));
        assertThat("recursive folders all exist", response, containsString("xs:integer\">3</wps:LiteralData>"));
    }

    @Test
    public void responseContainsSessionInfo()
            throws IOException, ParserConfigurationException, SAXException, XmlException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestResources.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        String payload = xmlPayload.toString();
        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
        assertThat(response, not(containsString("ExceptionReport")));
        assertThat(response, containsString("attached base packages:"));
        assertThat(response, containsString("locale:"));
        assertThat(response, containsString("<wps:ComplexData encoding=\"UTF-8\" mimeType=\"text/plain\">"));
        assertThat(response, containsString("methods"));
        assertThat(response, containsString("base"));
    }

    @Test
    public void responseContainsWarningsSection()
            throws IOException, ParserConfigurationException, SAXException, XmlException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestWarnings.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        String payload = xmlPayload.toString();
        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
        assertThat(response, containsString("<ows:Identifier>warnings</ows:Identifier>"));
        assertThat(response, containsString("mimeType=\"text/plain\">warning"));
        assertThat(response, containsString("Test warning 1"));
        assertThat(response, containsString("Test warning 4: This is the LAST warning"));
    }

    @Test
    public void responseContainsWarningsContent()
            throws IOException, ParserConfigurationException, SAXException, XmlException {

        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestWarnings.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        String payload = xmlPayload.toString();
        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
        assertThat(response, containsString("This is the LAST warning."));
    }

    @Test
    public void decribeProcess() throws IOException, ParserConfigurationException, SAXException {
        String identifier = "org.n52.wps.server.r.test.resources";
        String response = GetClient.sendRequest(wpsUrl,
                "Service=WPS&Request=DescribeProcess&Version=1.0.0&Identifier=" + identifier);

        assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
        assertThat(response, not(containsString("ExceptionReport")));
        assertThat(response, containsString(identifier));
        assertThat(response, containsString("<ows:Identifier>" + identifier + "</ows:Identifier>"));
    }

    @Test
    public void capabilitiesContainProcess() throws IOException, ParserConfigurationException, SAXException {
        String response = GetClient.sendRequest(wpsUrl, "Service=WPS&Request=GetCapabilities");

        assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
        assertThat(response, not(containsString("ExceptionReport")));
        assertThat(response, containsString("org.n52.wps.server.r.test.resources"));
        assertThat(response, containsString("org.n52.wps.server.r.test.calculator"));
        assertThat(response, containsString("org.n52.wps.server.r.test.image"));
    }

    @Test
    public void responseTypeIsImage() throws IOException, XmlException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestImage.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);
        String payload = xmlPayload.toString();
        payload = payload.replace("@@@size@@@", "420");

        String response = PostClient.sendRequest(wpsUrl, payload);
        assertThat(response.split("\n", 1)[0], containsString("PNG"));
        assertThat(response, response, not(containsString("ExceptionReport")));
    }

    @Test
    public void calculatorWorksCorrectly()
            throws IOException, ParserConfigurationException, SAXException, XmlException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestCalculator.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);
        String payload = xmlPayload.toString();

        Random rand = new Random();
        int a = rand.nextInt(100);
        payload = payload.replace("@@@a@@@", Integer.toString(a));
        int b = rand.nextInt(100);
        payload = payload.replace("@@@b@@@", Integer.toString(b));
        int op = rand.nextInt(3);
        String[] ops = new String[] { "+", "-", "*" };
        String opString = ops[op];
        payload = payload.replace("@@@op@@@", opString);
        int result = Integer.MIN_VALUE;
        if (opString.equals("+"))
            result = a + b;
        else if (opString.equals("-"))
            result = a - b;
        else if (opString.equals("*"))
            result = a * b;

        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat(AllTestsIT.parseXML(response), is(not(nullValue())));
        String expected = "dataType=\"xs:double\">" + Integer.toString(result) + ".0";
        assertThat(response, containsString(expected));
    }

    @Test
    public void wpsOffAnnotationWorks() throws XmlException, IOException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestWpsOff.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);
        String payload = xmlPayload.toString();
        String response = PostClient.sendRequest(wpsUrl, payload);

        String expected = "<wps:LiteralData dataType=\"xs:integer\">42</wps:LiteralData>";
        assertThat("Returned value is sum of provided ones, not sum of values defined in deactivated code.",
                response, containsString(expected));
    }

    @Test
    public void defaultValuesAreLoaded() throws XmlException, IOException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestDefaults.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);
        String payload = xmlPayload.toString();
        String response = PostClient.sendRequest(wpsUrl, payload);

        String expected = "<wps:LiteralData dataType=\"xs:integer\">42</wps:LiteralData>";
        assertThat("Returned value is sum of defaults, not sum of values defined in deactivated code.", response,
                containsString(expected));
    }

    @Test
    public void exceptionsOnIllegalInputs() throws XmlException, IOException {
        String[] illegalCommands = new String[] {
                // "\\x0022;", // FIXME Rserve can be crashed with this
                // "\u0071\u0075\u0069\u0074\u0028\u0029",
                // "<-", "a<-q", // result in WPS parsing error
                "=" };

        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestEcho.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        for (String cmd : illegalCommands) {
            String payload = xmlPayload.toString();
            payload = payload.replace("@@@data@@@", cmd);

            String expected = "illegal input";

            PostClient.checkForExceptionReport(wpsUrl, payload, HttpServletResponse.SC_BAD_REQUEST, expected, cmd);
        }
    }

    @Test
    public void syntaxErrorOnIllegalInputs() throws XmlException, IOException {
        String[] illegalCommands = new String[] { "\"\";quit(\"no\");", "setwd('/root/')", "setwd(\"c:/\")" };

        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestEcho.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        for (String cmd : illegalCommands) {
            String payload = xmlPayload.toString();
            payload = payload.replace("@@@data@@@", cmd);

            String expected = "eval failed";
            PostClient.checkForExceptionReport(wpsUrl, payload, HttpServletResponse.SC_BAD_REQUEST, expected);
        }
    }

    @Test
    public void replacementsOnIllegalInputs() throws XmlException, IOException {
        String[] illegalCommands = new String[] { "unlink(getwd())", "q();", "quit()", "%lt;-",
                // "system('format hardisk')",
                "quit(\\\"no\\\");inputVariable;" };

        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestEcho.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        for (String cmd : illegalCommands) {
            String payload = xmlPayload.toString();
            payload = payload.replace("@@@data@@@", cmd);

            String response = PostClient.sendRequest(wpsUrl, payload);

            assertThat("Response is not an exception", response, not(containsString("ExceptionReport")));
            // assertThat("Response contains an echo of '" + cmd + "'", response, containsString(cmd));
        }
    }

    @Test
    public void renamingDoesNotAffectScript() throws XmlException, IOException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestEcho.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        String data = UUID.randomUUID().toString();
        String payload = xmlPayload.toString();
        payload = payload.replace("@@@data@@@", data);

        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat("Response is not an exception", response, not(containsString("ExceptionReport")));
        assertThat("Response contains an echo of '" + data + "'", response, containsString(data));
    }

    @Test
    public void csvResponseInlineWorks() throws XmlException, IOException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestCSV.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        String payload = xmlPayload.toString();
        payload = payload.replace("@@@ref@@@", Boolean.toString(false));
        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat("Response is not an exception", response, not(containsString("ExceptionReport")));
        assertThat("Response contains mime type", response, containsString("mimeType=\"text/csv\""));

        assertThat("Response contains test data names", response,
                containsString("\"cadmium\",\"copper\",\"lead\",\"zinc\""));
    }

    @Test
    public void csvResponseReferenceWorks() throws XmlException, IOException {
        URL resource = Wps4rIT.class.getResource("/R/ExecuteTestCSV.xml");
        XmlObject xmlPayload = XmlObject.Factory.parse(resource);

        String payload = xmlPayload.toString();
        payload = payload.replace("@@@ref@@@", Boolean.toString(true));
        String response = PostClient.sendRequest(wpsUrl, payload);

        assertThat("Response is not an exception", response, not(containsString("ExceptionReport")));
        assertThat("Response contains mime type", response, containsString("mimeType=\"text/csv\""));

        String urlString = response.substring(response.indexOf("http", response.indexOf("text/csv")));
        urlString = urlString.substring(0, urlString.indexOf("\""));
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.connect();
        String contentType = connection.getContentType();
        assertThat("Response content type is correct", contentType, is("text/csv"));

        StringWriter writer = new StringWriter();
        IOUtils.copy(connection.getInputStream(), writer);
        String csv = writer.toString();

        assertThat("CSV file contains test data names", csv,
                containsString("\"cadmium\",\"copper\",\"lead\",\"zinc\""));
    }

}