/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wps;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.geoserver.data.test.MockData.PRIMITIVEGEOFEATURE;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import javax.xml.namespace.QName;
import org.apache.commons.codec.binary.Base64;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.custommonkey.xmlunit.exceptions.XpathException;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.data.test.SystemTestData.LayerProperty;
import org.geoserver.ows.util.KvpUtils;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.resource.Resource;
import org.geoserver.test.RemoteOWSTestSupport;
import org.geoserver.wps.executor.ExecutionStatus;
import org.geoserver.wps.executor.ProcessState;
import org.geoserver.wps.executor.ProcessStatusTracker;
import org.geoserver.wps.resource.ProcessArtifactsStore;
import org.geoserver.wps.resource.WPSResourceManager;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.gml3.GMLConfiguration;
import org.geotools.ows.v1_1.OWSConfiguration;
import org.geotools.process.ProcessException;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.xml.PreventLocalEntityResolver;
import org.geotools.xml.Parser;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeatureType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.w3c.dom.Document;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.WKTReader;
import net.opengis.ows11.BoundingBoxType;
public class ExecuteTest extends WPSTestSupport {
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
testData.addVectorLayer(SystemTestData.PRIMITIVEGEOFEATURE, getCatalog());
String pgf = PRIMITIVEGEOFEATURE.getLocalPart();
testData.addVectorLayer(new QName("http://foo.org", pgf, "foo" ), new HashMap<LayerProperty,Object>(), pgf + ".properties", MockData.class, getCatalog());
}
@Before
public void oneTimeSetUp() throws Exception {
WPSInfo wps = getGeoServer().getService(WPSInfo.class);
// want at least two asynchronous processes to test concurrency
wps.setMaxAsynchronousProcesses(Math.max(2, wps.getMaxAsynchronousProcesses()));
getGeoServer().save(wps);
}
@Before
public void setUpInternal() throws Exception {
// make extra sure we don't have anything else going
MonkeyProcess.clearCommands();
}
@Test
public void testEntityExpansion() throws Exception {
String xml =
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" +
"<!DOCTYPE foo [<!ELEMENT foo ANY >\n" +
" <!ENTITY xxe SYSTEM \"FILE:///file/not/there?.XSD\" >]>\n" +
"<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>JTS:buffer</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>&xxe;</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData>" +
"<gml:Polygon xmlns:gml='http://www.opengis.net/gml'>" +
"<gml:exterior>" +
"<gml:LinearRing>" +
"<gml:coordinates>1 1 2 1 2 2 1 2 1 1</gml:coordinates>" +
"</gml:LinearRing>" +
"</gml:exterior>" +
"</gml:Polygon>" +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output>" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
// System.out.println(xml);
Document d = postAsDOM( "wps", xml );
checkValidationErrors(d);
// print(d);
String text = xp.evaluate("//ows:ExceptionText", d);
assertTrue(text.contains(PreventLocalEntityResolver.ERROR_MESSAGE_BASE));
}
@Test
public void testDataInline() throws Exception { // Standard Test A.4.4.2, A.4.4.4
String xml =
"<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>JTS:buffer</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>geom</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData>" +
"<gml:Polygon xmlns:gml='http://www.opengis.net/gml'>" +
"<gml:exterior>" +
"<gml:LinearRing>" +
"<gml:coordinates>1 1 2 1 2 2 1 2 1 1</gml:coordinates>" +
"</gml:LinearRing>" +
"</gml:exterior>" +
"</gml:Polygon>" +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output>" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
// System.out.println(xml);
Document d = postAsDOM( "wps", xml );
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData/gml:Polygon", d);
}
@Test
public void testCDataOutput() throws Exception {
// @formatter:off
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>JTS:buffer</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>geom</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData>" +
"<gml:Polygon xmlns:gml='http://www.opengis.net/gml'>" +
"<gml:exterior>" +
"<gml:LinearRing>" +
"<gml:coordinates>1 1 2 1 2 2 1 2 1 1</gml:coordinates>" +
"</gml:LinearRing>" +
"</gml:exterior>" +
"</gml:Polygon>" +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output mimeType=\"application/wkt\">" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
// @formatter:on
// System.out.println(xml);
Document d = postAsDOM( "wps", xml );
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
String wkt = xp.evaluate("/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData", d);
assertThat(new WKTReader().read(wkt), instanceOf(Polygon.class));
}
@Test
public void testDataInlineRawOutput() throws Exception { // Standard Test A.4.4.3
String xml =
"<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>JTS:buffer</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>geom</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData>" +
"<gml:Polygon xmlns:gml='http://www.opengis.net/gml'>" +
"<gml:exterior>" +
"<gml:LinearRing>" +
"<gml:coordinates>1 1 2 1 2 2 1 2 1 1</gml:coordinates>" +
"</gml:LinearRing>" +
"</gml:exterior>" +
"</gml:Polygon>" +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
" <wps:RawDataOutput>" +
" <ows:Identifier>result</ows:Identifier>" +
" </wps:RawDataOutput>" +
" </wps:ResponseForm>" +
"</wps:Execute>";
Document d = postAsDOM( "wps", xml );
// print(d);
checkValidationErrors(d, new GMLConfiguration());
assertEquals( "gml:Polygon", d.getDocumentElement().getNodeName() );
}
@Test
public void testWKTInlineRawOutput() throws Exception { // Standard Test A.4.4.3
String xml =
"<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>JTS:buffer</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>geom</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData mimeType=\"application/wkt\">" +
"<![CDATA[POLYGON((1 1, 2 1, 2 2, 1 2, 1 1))]]>" +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
" <wps:RawDataOutput mimeType=\"application/wkt\">" +
" <ows:Identifier>result</ows:Identifier>" +
" </wps:RawDataOutput>" +
" </wps:ResponseForm>" +
"</wps:Execute>";
// print(dom(new StringInputStream("<?xml version=\"1.0\" encoding=\"UTF-16\"?>\n" + xml)));
MockHttpServletResponse response = postAsServletResponse( "wps", xml );
// System.out.println(response.getOutputStreamContent());
assertEquals("application/wkt", response.getContentType());
String cd = response.getHeader("Content-Disposition");
assertTrue(cd.endsWith("filename=result.wkt"));
Geometry g = new WKTReader().read(response.getContentAsString());
Assert.assertTrue(g instanceof Polygon);
}
@Test
public void testWKTInlineKVPRawOutput() throws Exception {
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=JTS:buffer" +
"&DataInputs=" + urlEncode("geom=POLYGON((1 1, 2 1, 2 2, 1 2, 1 1))@mimetype=application/wkt;distance=1") +
"&RawDataOutput=" + urlEncode("result=@mimetype=application/wkt");
MockHttpServletResponse response = getAsServletResponse(request);
// System.out.println(response.getOutputStreamContent());
assertEquals("application/wkt", response.getContentType());
Geometry g = new WKTReader().read(response.getContentAsString());
Assert.assertTrue(g instanceof Polygon);
}
@Test
public void testFeatureCollectionInline() throws Exception { // Standard Test A.4.4.2, A.4.4.4
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>features</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData>" +
readFileIntoString("states-FeatureCollection.xml") +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>10</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>attributeName</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData></wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output>" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
Document d = postAsDOM( "wps", xml );
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData/wfs:FeatureCollection", d);
}
/**
* Test GEOS-5663 https://osgeo-org.atlassian.net/browse/GEOS-5663
* Location is removed from collections
*
* @throws Exception
*/
@Test
public void testFeatureCollectionInlineWithLocation() throws Exception {
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:Nearest</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>features</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData>" +
readFileIntoString("places-FeatureCollectionLocation.xml") +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>"+
"<ows:Identifier>point</ows:Identifier>"+
"<wps:Data>"+
"<wps:ComplexData mimeType=\"text/xml; subtype=gml/3.1.1\"><![CDATA[POINT(-96 41)]]></wps:ComplexData>"+
"</wps:Data>"+
"</wps:Input>"+
"<wps:Input>"+
"<ows:Identifier>crs</ows:Identifier>"+
"<wps:Data>"+
"<wps:LiteralData>EPSG:4326</wps:LiteralData>"+
"</wps:Data>"+
"</wps:Input>"+
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output>" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
Document d = postAsDOM( "wps", xml );
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData/wfs:FeatureCollection", d);
}
@Test
public void testFeatureCollectionInlineBoundedBy() throws Exception { // Standard Test A.4.4.2, A.4.4.4
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>features</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData mimeType=\"text/xml; subtype=wfs-collection/1.0\">" +
readFileIntoString("restricted-FeatureCollection.xml") +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1000</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output>" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
Document d = postAsDOM( "wps", xml );
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData/wfs:FeatureCollection", d);
assertXpathEvaluatesTo("0", "count(//feature:boundedBy)", d);
}
@Test
public void testFeatureCollectionInlineKVP() throws Exception {
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:BufferFeatureCollection" +
"&DataInputs=" + urlEncode("features=" + readFileIntoString("states-FeatureCollection.xml") + "@mimetype=application/wfs-collection-1.1;distance=10") +
"&ResponseDocument=" + urlEncode("result");
Document d = getAsDOM(request);
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData/wfs:FeatureCollection", d);
}
@Test
public void testReferenceOutputXML() throws Exception { // Standard Test A.4.4.2, A.4.4.4
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>features</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData mimeType=\"text/xml; subtype=wfs-collection/1.0\">" +
readFileIntoString("restricted-FeatureCollection.xml") +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1000</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output asReference=\"true\">" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
Document d = postAsDOM( "wps", xml );
// check we got a valid response with the document as a reference
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists("/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Reference", d);
XpathEngine xpath = XMLUnit.newXpathEngine();
String fullLocation = xpath.evaluate("/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Reference/@href", d);
String resourceLocation = fullLocation.substring(fullLocation.indexOf('?') - 3);
d = getAsDOM(resourceLocation);
assertXpathExists("wfs:FeatureCollection", d);
}
@Test
public void testReferenceOutputKVP() throws Exception {
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:BufferFeatureCollection" +
"&DataInputs=" + urlEncode("features=" + readFileIntoString("states-FeatureCollection.xml") +
"@mimetype=application/wfs-collection-1.1;distance=10") +
"&ResponseDocument=" + urlEncode("result=@asReference=true");
Document d = getAsDOM(request);
// print(d);
// check we got a valid response with the document as a reference
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists("/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Reference", d);
XpathEngine xpath = XMLUnit.newXpathEngine();
String fullLocation = xpath.evaluate("/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Reference/@href", d);
String resourceLocation = fullLocation.substring(fullLocation.indexOf('?') - 3);
MockHttpServletResponse response = getAsServletResponse(resourceLocation);
assertEquals("text/xml; subtype=wfs-collection/1.0", response.getContentType());
d = dom(new ByteArrayInputStream( response.getContentAsString().getBytes()));
assertXpathExists("wfs:FeatureCollection", d);
}
@Test
public void testFeatureCollectionFileReference() throws Exception { // Standard Test A.4.4.2, A.4.4.4
URL collectionURL = getClass().getResource("states-FeatureCollection.xml");
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' xmlns:xlink=\"http://www.w3.org/1999/xlink\" " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>features</ows:Identifier>" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.1\" " +
"xlink:href=\"" + collectionURL.toExternalForm() + "\"/>\n" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>10</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output>" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
// System.out.println(postAsServletResponse("wps", xml).getOutputStreamContent());
Document d = postAsDOM( "wps", xml );
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData/wfs:FeatureCollection", d);
}
@Test
public void testFeatureCollectionFileReferenceKVP() throws Exception {
URL collectionURL = getClass().getResource("states-FeatureCollection.xml");
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:BufferFeatureCollection" +
"&DataInputs=" + urlEncode("features=@mimetype=application/wfs-collection-1.1@xlink:href="
+ collectionURL.toExternalForm() + ";distance=10") + "&ResponseDocument=" + urlEncode("result");
Document d = getAsDOM(request);
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathExists(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output/wps:Data/wps:ComplexData/wfs:FeatureCollection", d);
}
@Test
public void testInlineGeoJSON() throws Exception {
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>features</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData mimeType=\"application/json\"><![CDATA[" +
readFileIntoString("states-FeatureCollection.json") +
"]]></wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>10</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:RawDataOutput mimeType=\"application/json\">" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:RawDataOutput>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
MockHttpServletResponse r = postAsServletResponse("wps", xml);
assertEquals("application/json", r.getContentType());
// System.out.println(r.getOutputStreamContent());
FeatureCollection fc = new FeatureJSON().readFeatureCollection(r.getContentAsString());
assertEquals(2, fc.size());
}
@Test
public void testInlineShapezip() throws Exception {
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>features</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData mimeType=\"application/zip\" encoding=\"base64\"><![CDATA[" +
readFileIntoString("states-zip-base64.txt") +
"]]></wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>10</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:RawDataOutput mimeType=\"application/json\">" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:RawDataOutput>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
MockHttpServletResponse r = postAsServletResponse("wps", xml);
// System.out.println(r.getOutputStreamContent());
assertEquals("application/json", r.getContentType());
// System.out.println(r.getOutputStreamContent());
FeatureCollection fc = new FeatureJSON().readFeatureCollection(r.getContentAsString());
assertEquals(2, fc.size());
}
@Test
public void testShapeZip() throws Exception {
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:xlink=\"http://www.w3.org/1999/xlink\" " +
"xmlns:wps='http://www.opengis.net/wps/1.0.0' xmlns:wfs='http://www.opengis.net/wfs' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:BufferFeatureCollection</ows:Identifier>" +
"<wps:DataInputs>" +
" <wps:Input>\n" +
"<ows:Identifier>features</ows:Identifier>" +
"<wps:Data>" +
"<wps:ComplexData>" +
readFileIntoString("states-FeatureCollection.xml") +
"</wps:ComplexData>" +
"</wps:Data>" +
"</wps:Input>" +
"<wps:Input>" +
"<ows:Identifier>distance</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>10</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:RawDataOutput mimeType=\"application/zip\">" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:RawDataOutput>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
MockHttpServletResponse r = postAsServletResponse("wps", xml);
assertEquals("application/zip", r.getContentType());
checkShapefileIntegrity(new String[] {"states"}, getBinaryInputStream(r));
}
/**
* Tests a process execution with a BoudingBox as the output and check internal layer
* request handling as well
*/
@Test
public void testBoundsPost() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" xlink:href=\"http://geoserver/wfs\" method=\"POST\">\n" +
" <wps:Body>\n" +
" <wfs:GetFeature service=\"WFS\" version=\"1.0.0\">\n" +
" <wfs:Query typeName=\"cite:Streams\"/>\n" +
" </wfs:GetFeature>\n" +
" </wps:Body>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
Document dom = postAsDOM(root(), request);
print(dom);
assertXpathEvaluatesTo("-4.0E-4 -0.0024", "/ows:BoundingBox/ows:LowerCorner", dom);
assertXpathEvaluatesTo("0.0036 0.0024", "/ows:BoundingBox/ows:UpperCorner", dom);
}
/**
* Tests a process execution with a BoudingBox as the output and check internal layer
* request handling as well
*/
@Test
public void testBoundsGet() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" xlink:href=\"http://geoserver/wfs?service=WFS&request=GetFeature&typename=cite:Streams\" method=\"GET\"/>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
Document dom = postAsDOM(root(), request);
// print(dom);
assertXpathEvaluatesTo("-4.0E-4 -0.0024", "/ows:BoundingBox/ows:LowerCorner", dom);
assertXpathEvaluatesTo("0.0036 0.0024", "/ows:BoundingBox/ows:UpperCorner", dom);
}
/**
* Tests a process grabbing a remote layer
*/
@Test
public void testRemoteGetWFS10Layer() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" " +
" xlink:href=\"http://demo.opengeo.org/geoserver/wfs?request=GetFeature&service=wfs&version=1.0.0&typeName=topp:states&featureid=states.1\" />\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
executeState1BoundsTest(request, "GET WFS 1.0");
}
/**
* Tests a process grabbing a remote layer
*/
@Test
public void testRemotePostWFS10Layer() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" " +
" xlink:href=\"http://demo.opengeo.org/geoserver/wfs\" method=\"POST\">\n" +
" <wps:Body>\n" +
"<![CDATA[<wfs:GetFeature service=\"WFS\" version=\"1.0.0\"\n" +
" outputFormat=\"GML2\"\n" +
" xmlns:topp=\"http://www.openplans.org/topp\"\n" +
" xmlns:wfs=\"http://www.opengis.net/wfs\"\n" +
" xmlns:ogc=\"http://www.opengis.net/ogc\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://www.opengis.net/wfs\n" +
" http://schemas.opengis.net/wfs/1.0.0/WFS-basic.xsd\">\n" +
" <wfs:Query typeName=\"topp:states\">\n" +
" <ogc:Filter>\n" +
" <ogc:FeatureId fid=\"states.1\"/>\n" +
" </ogc:Filter>\n" +
" </wfs:Query>\n" +
"</wfs:GetFeature>]]>" +
" </wps:Body>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
executeState1BoundsTest(request, "POST WFS 1.0");
}
/**
* Tests a process grabbing a remote layer
*/
@Test
public void testRemoteBodyReferencePostWFS10Layer() throws Exception {
URL getFeatureURL = getClass().getResource("getFeature.xml");
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" " +
" xlink:href=\"http://demo.opengeo.org/geoserver/wfs\" method=\"POST\">\n" +
" <wps:BodyReference xlink:href=\"" + getFeatureURL.toExternalForm() + "\"/>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
executeState1BoundsTest(request, "POST WFS 1.0");
}
/**
* Tests a process grabbing a remote layer
*/
@Test
public void testRemoteGetWFS11Layer() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.1\" " +
" xlink:href=\"http://demo.opengeo.org/geoserver/wfs?request=GetFeature&service=wfs&version=1.1&typeName=topp:states&featureid=states.1\" />\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
// System.out.println(request);
executeState1BoundsTest(request, "GET WFS 1.1");
}
/**
* Tests a process grabbing a remote layer
*/
@Test
public void testRemotePostWFS11Layer() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.1\" " +
" xlink:href=\"http://demo.opengeo.org/geoserver/wfs\" method=\"POST\">\n" +
" <wps:Body>\n" +
"<![CDATA[<wfs:GetFeature service=\"WFS\" version=\"1.1.0\"\n" +
" xmlns:topp=\"http://www.openplans.org/topp\"\n" +
" xmlns:wfs=\"http://www.opengis.net/wfs\"\n" +
" xmlns:ogc=\"http://www.opengis.net/ogc\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xsi:schemaLocation=\"http://www.opengis.net/wfs\n" +
" http://schemas.opengis.net/wfs/1.1.0/wfs.xsd\">\n" +
" <wfs:Query typeName=\"topp:states\">\n" +
" <ogc:Filter>\n" +
" <ogc:FeatureId fid=\"states.1\"/>\n" +
" </ogc:Filter>\n" +
" </wfs:Query>\n" +
"</wfs:GetFeature>]]>" +
" </wps:Body>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
executeState1BoundsTest(request, "POST WFS 1.1");
}
@Test
public void testProcessChaining() throws Exception {
// chain two JTS processes
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>JTS:area</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>geom</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=gml/3.1.1\" xlink:href=\"http://geoserver/wps\" method=\"POST\">\n" +
" <wps:Execute>\n" +
" <ows:Identifier>JTS:buffer</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>geom</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:ComplexData mimeType=\"application/wkt\"><![CDATA[POINT(0 0)]]></wps:ComplexData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" <wps:Input>\n" +
" <ows:Identifier>distance</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:LiteralData>10</wps:LiteralData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput mimeType=\"text/xml; subtype=gml/3.1.1\">\n" +
" <ows:Identifier>result</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
" </wps:Execute>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>result</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
MockHttpServletResponse resp = postAsServletResponse(root(), xml);
assertEquals("text/plain", resp.getContentType());
// the result is inaccurate since the buffer is just a poor approximation of a circle
Assert.assertTrue(resp.getContentAsString().matches("312\\..*"));
}
@Test
public void testNoResponseForm() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><wps:Execute xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" service=\"WPS\" version=\"1.0.0\">\n" +
" <ows:Identifier>JTS:area</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>geom</ows:Identifier>\n" +
" <wps:Reference xlink:href=\"http://geoserver/wps\" method=\"POST\" mimeType=\"application/xml\">\n" +
" <wps:Execute service=\"WPS\" version=\"1.0.0\">\n" +
" <ows:Identifier>JTS:union</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>geom</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:ComplexData mimeType=\"application/wkt\"><![CDATA[POLYGON((20 10, 30 0, 40 10, 30 20, 20 10))]]></wps:ComplexData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" <wps:Input>\n" +
" <ows:Identifier>geom</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:ComplexData mimeType=\"application/wkt\"><![CDATA[POLYGON((2 1, 3 0, 4 1, 3 2, 2 1))]]></wps:ComplexData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" </wps:Execute>\n" +
"\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
"</wps:Execute>";
Document dom = postAsDOM(root(), xml);
print(dom);
}
@Test
public void testProcessChainingKVP() throws Exception {
String nested = "http://geoserver/wps?service=WPS&version=1.0.0&request=Execute&Identifier=JTS:buffer" +
"&DataInputs=" + urlEncode("geom=POINT(0 0)@mimetype=application/wkt;distance=10") + "&RawDataOutput=result";
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=JTS:area" +
"&DataInputs=" + urlEncode("geom=@href=" + nested) + "&RawDataOutput=result";
MockHttpServletResponse resp = getAsServletResponse(request);
assertEquals("text/plain", resp.getContentType());
// the result is inaccurate since the buffer is just a poor approximation of a circle
Assert.assertTrue(resp.getContentAsString().matches("312\\..*"));
}
@Test
public void testProcessFailure() throws Exception {
// have the monkey throw an exception
MonkeyProcess.exception("x1", new ProcessException("Sorry dude, things went pear shaped..."), false);
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&DataInputs=" + urlEncode("id=x1");
Document dom = getAsDOM(request);
checkValidationErrors(dom);
print(dom);
assertXpathExists("//wps:ProcessFailed", dom);
assertXpathEvaluatesTo("Process failed during execution\nSorry dude, things went pear shaped...",
"//wps:ProcessFailed/ows:ExceptionReport/ows:Exception/ows:ExceptionText", dom);
}
@Test
public void testStoredNoStatus() throws Exception {
// submit asynch request with no updates
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&storeExecuteResponse=true&DataInputs=" + urlEncode("id=x2");
Document dom = getAsDOM(request);
assertXpathExists("//wps:ProcessAccepted", dom);
XpathEngine xpath = XMLUnit.newXpathEngine();
String fullStatusLocation = xpath.evaluate("//wps:ExecuteResponse/@statusLocation", dom);
String statusLocation = fullStatusLocation.substring(fullStatusLocation.indexOf('?') - 3);
// we move the clock forward, but we asked no status, nothing should change
MonkeyProcess.progress("x2", 50f, true);
dom = getAsDOM(statusLocation);
print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo("26", "//wps:ProcessStarted/@percentCompleted", dom);
// now schedule the exit and wait for it to exit
ListFeatureCollection fc = collectionOfThings();
MonkeyProcess.exit("x2", fc, true);
dom = waitForProcessEnd(statusLocation, 60);
assertXpathExists("//wps:ProcessSucceeded", dom);
}
@Test
public void testStoredWithStatus() throws Exception {
// submit asynch request with no updates
String statusLocation = submitMonkey("x3");
// we move the clock forward, but we asked no status, nothing should change
MonkeyProcess.progress("x3", 10f, true);
Document dom = getAsDOM(statusLocation);
print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo("6", "//wps:ProcessStarted/@percentCompleted", dom);
// we move the clock forward, but we asked no status, nothing should change
MonkeyProcess.progress("x3", 50f, true);
dom = getAsDOM(statusLocation);
// print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo("26", "//wps:ProcessStarted/@percentCompleted", dom);
assertXpathEvaluatesTo("Currently at 10.0", "//wps:ProcessStarted", dom);
// now schedule the exit and wait for it to exit
MonkeyProcess.exit("x3", collectionOfThings(), true);
dom = waitForProcessEnd(statusLocation, 60);
// print(dom);
assertXpathExists("//wps:ProcessSucceeded", dom);
}
/**
* https://osgeo-org.atlassian.net/browse/GEOS-5208
*/
@Test
public void testChainedProgress() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:CollectGeometries</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" xlink:href=\"http://geoserver/wps\" method=\"POST\">\n" +
" <wps:Body>\n" +
" <wps:Execute version=\"1.0.0\" service=\"WPS\">\n" +
" <ows:Identifier>gs:Monkey</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>id</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:LiteralData>chained-monkey</wps:LiteralData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput mimeType=\"text/xml; subtype=gml/3.1.1\">\n" +
" <ows:Identifier>result</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
" </wps:Execute>\n" +
" </wps:Body>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
"<wps:ResponseDocument status=\"true\" storeExecuteResponse=\"true\">"
+
"<wps:Output asReference=\"true\">" +
"<ows:Identifier>result</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
//
// MonkeyProcess.exit("chained-monkey", collectionOfThings(), false);
Document dom = postAsDOM("wfs", request);
String statusLocation = getStatusLocation(dom);
MonkeyProcess.progress("chained-monkey", 10f, true);
dom = getAsDOM(statusLocation);
// print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo("3", "//wps:ProcessStarted/@percentCompleted", dom);
MonkeyProcess.progress("chained-monkey", 50f, true);
dom = getAsDOM(statusLocation);
// print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo("17", "//wps:ProcessStarted/@percentCompleted", dom);
MonkeyProcess.exit("chained-monkey", collectionOfThings(), true);
// no way to control the collect geometry process, we just wait
waitForProcessEnd(statusLocation, 60);
}
/**
* https://osgeo-org.atlassian.net/browse/GEOS-5208
*/
@Test
public void testTripleChainedProgress() throws Exception {
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Monkey</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>id</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:LiteralData>m1</wps:LiteralData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" <wps:Input>\n" +
" <ows:Identifier>fc</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" xlink:href=\"http://geoserver/wps\" method=\"POST\">\n" +
" <wps:Body>\n" +
" <wps:Execute version=\"1.0.0\" service=\"WPS\">\n" +
" <ows:Identifier>gs:Monkey</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>id</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:LiteralData>m2</wps:LiteralData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" <wps:Input>\n" +
" <ows:Identifier>fc</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" xlink:href=\"http://geoserver/wps\" method=\"POST\">\n" +
" <wps:Body>\n" +
" <wps:Execute version=\"1.0.0\" service=\"WPS\">\n" +
" <ows:Identifier>gs:Monkey</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>id</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:LiteralData>m3</wps:LiteralData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput mimeType=\"text/xml; subtype=gml/3.1.1\">\n" +
" <ows:Identifier>result</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
" </wps:Execute>\n" +
" </wps:Body>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" <wps:Input>\n" +
" <ows:Identifier>extra</ows:Identifier>\n" +
" <wps:Data>\n" +
" <wps:LiteralData>extra value</wps:LiteralData>\n" +
" </wps:Data>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput mimeType=\"text/xml; subtype=gml/3.1.1\">\n" +
" <ows:Identifier>result</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
" </wps:Execute>\n" +
" </wps:Body>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:ResponseDocument status=\"true\" storeExecuteResponse=\"true\">" +
" <wps:Output asReference=\"true\">" +
" <ows:Identifier>result</ows:Identifier>" +
" </wps:Output>" +
" </wps:ResponseDocument>" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
//
// MonkeyProcess.exit("chained-monkey", collectionOfThings(), false);
Document dom = postAsDOM("wfs", request);
String statusLocation = getStatusLocation(dom);
MonkeyProcess.progress("m3", 50f, true);
assertProgress(statusLocation, "13");
MonkeyProcess.exit("m3", collectionOfThings(), true);
assertProgress(statusLocation, "25");
MonkeyProcess.progress("m2", 50f, true);
assertProgress(statusLocation, "38");
MonkeyProcess.exit("m2", collectionOfThings(), true);
assertProgress(statusLocation, "50");
MonkeyProcess.progress("m1", 100f, true);
assertProgress(statusLocation, "75");
MonkeyProcess.exit("m1", collectionOfThings(), true);
// wait for completion
waitForProcessEnd(statusLocation, 60);
}
@Test
public void testAsynchFailEncode() throws Exception {
// submit asynch request with no updates
String statusLocation = submitMonkey("x5");
// now schedule the exit and wait for it to exit
MonkeyProcess.exit("x5", bombOutCollection(), true);
Document dom = waitForProcessEnd(statusLocation, 60);
// print(dom);
assertXpathExists("//wps:ProcessFailed", dom);
}
@Test
public void testDismissDuringEncoding() throws Exception {
// submit asynch request with no updates
String statusLocation = submitMonkey("x3");
// grab the execution id
Map<String, Object> kvp = KvpUtils.parseQueryString(statusLocation);
String executionId = (String) kvp.get("executionId");
// make it progress until the end
MonkeyProcess.progress("x3", 100f, true);
Document dom = getAsDOM(statusLocation);
// print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo("50", "//wps:ProcessStarted/@percentCompleted", dom);
// have it return a collection that we can block
final AtomicBoolean returnFlag = new AtomicBoolean(false);
SimpleFeatureType featureType = buildSampleFeatureType();
ListFeatureCollection fc = new ListFeatureCollection(featureType) {
@Override
public SimpleFeatureIterator features() {
while (returnFlag.get() == false) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
}
return super.features();
}
@Override
protected Iterator openIterator() {
while (returnFlag.get() == false) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
}
}
return super.openIterator();
}
};
MonkeyProcess.exit("x3", fc, true);
// grab the status tracker
ProcessStatusTracker statusTracker = GeoServerExtensions.bean(ProcessStatusTracker.class,
applicationContext);
// now issue the dismiss, while the process is blocked trying to write out the collection
dom = getAsDOM("wps?service=WPS&version=1.0.0&request=Dismiss&executionId=" + executionId);
// print(dom);
assertXpathExists("//wps:ProcessFailed", dom);
// on the status tracker, the process is being dismissed or it's already gone
ExecutionStatus status = statusTracker.getStatus(executionId);
Assert.assertTrue(status == null || ProcessState.DISMISSING.equals(status.getPhase()));
// let it move on and wait for end
returnFlag.set(true);
// wait until the execution actually ends
while (status != null && status.getPhase() == ProcessState.DISMISSING) {
Thread.sleep(50);
status = statusTracker.getStatus(executionId);
if (status != null) {
// the status must switch from dismissing to plain gone
Assert.assertEquals(ProcessState.DISMISSING, status.getPhase());
}
}
// at this point also check there is no resource left
WPSResourceManager resources = GeoServerExtensions.bean(WPSResourceManager.class,
applicationContext);
ProcessArtifactsStore artifactsStore = resources.getArtifactsStore();
List<Resource> executionResources = artifactsStore.listExecutionResourcess();
for (Resource r : executionResources) {
assertNotEquals(executionId, r.name());
}
}
@Test
public void testDismissDuringExecution() throws Exception {
// submit asynch request with no updates
String statusLocation = submitMonkey("x3");
// grab the execution id
Map<String, Object> kvp = KvpUtils.parseQueryString(statusLocation);
String executionId = (String) kvp.get("executionId");
// make it progress and complete
MonkeyProcess.progress("x3", 10f, true);
Document dom = getAsDOM(statusLocation);
// print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo("6", "//wps:ProcessStarted/@percentCompleted", dom);
// grab the status tracker
ProcessStatusTracker statusTracker = GeoServerExtensions.bean(ProcessStatusTracker.class,
applicationContext);
// now issue a dismiss
dom = getAsDOM("wps?service=WPS&version=1.0.0&request=Dismiss&executionId=" + executionId);
print(dom);
assertXpathExists("//wps:ProcessFailed", dom);
// on the status tracker, the process is being dismissed
ExecutionStatus status = statusTracker.getStatus(executionId);
Assert.assertEquals(ProcessState.DISMISSING, status.getPhase());
// issue it again, we should be told the process does not exists
dom = getAsDOM("wps?service=WPS&version=1.0.0&request=Dismiss&executionId=" + executionId);
print(dom);
checkOws11Exception(dom);
// same goes when using the status url
// still being dismissed
status = statusTracker.getStatus(executionId);
Assert.assertEquals(ProcessState.DISMISSING, status.getPhase());
dom = getAsDOM(statusLocation);
checkOws11Exception(dom);
// make the process move forward so that it will notice the failure and bomb
MonkeyProcess.progress("x3", 50f, true);
// wait until the execution actually ends
while (status != null && status.getPhase() == ProcessState.DISMISSING) {
Thread.sleep(50);
status = statusTracker.getStatus(executionId);
if (status != null) {
// the status must switch from dismissing to plain gone
Assert.assertEquals(ProcessState.DISMISSING, status.getPhase());
}
}
// at this point also check there is no resource left
WPSResourceManager resources = GeoServerExtensions.bean(WPSResourceManager.class,
applicationContext);
ProcessArtifactsStore artifactsStore = resources.getArtifactsStore();
List<Resource> executionResources = artifactsStore.listExecutionResourcess();
for (Resource r : executionResources) {
assertNotEquals(executionId, r.name());
}
}
@Test
public void testDismissAfterCompletion() throws Exception {
// submit asynch request with no updates
String statusLocation = submitMonkey("x3");
// grab the execution id
Map<String, Object> kvp = KvpUtils.parseQueryString(statusLocation);
String executionId = (String) kvp.get("executionId");
// make it progress and complete
MonkeyProcess.exit("x3", collectionOfThings(), true);
Document dom = waitForProcessEnd(statusLocation, 60);
// print(dom);
assertXpathExists("//wps:ProcessSucceeded", dom);
// grab the status tracker, check the process succeeded
ProcessStatusTracker statusTracker = GeoServerExtensions.bean(ProcessStatusTracker.class,
applicationContext);
ExecutionStatus status = statusTracker.getStatus(executionId);
Assert.assertEquals(ProcessState.SUCCEEDED, status.getPhase());
// grab the resource manager, the output collection is also there
WPSResourceManager resources = GeoServerExtensions.bean(WPSResourceManager.class,
applicationContext);
Resource resource = resources.getStoredResponse(executionId);
Assert.assertEquals(Resource.Type.RESOURCE, resource.getType());
// now dismiss it
dom = getAsDOM("wps?service=WPS&version=1.0.0&request=Dismiss&executionId=" + executionId);
assertXpathExists("//wps:ProcessFailed", dom);
// on the status tracker, the process is now gone
status = statusTracker.getStatus(executionId);
Assert.assertNull(status);
// and there is no trace of its resources either
ProcessArtifactsStore artifactsStore = resources.getArtifactsStore();
List<Resource> executionResources = artifactsStore.listExecutionResourcess();
for (Resource r : executionResources) {
assertNotEquals(executionId, r.name());
}
}
@Test
public void testConcurrentRequests() throws Exception {
// submit first
String statusLocation1 = submitMonkey("one");
String statusLocation2 = submitMonkey("two");
// make the report progress
MonkeyProcess.progress("one", 10f, true);
MonkeyProcess.progress("two", 10f, true);
// make sure both were started and are running, input parsing was assumed to be 1%
assertProgress(statusLocation1, "6");
assertProgress(statusLocation2, "6");
// now schedule the exit and wait for it to exit
MonkeyProcess.exit("one", collectionOfThings(), true);
MonkeyProcess.exit("two", collectionOfThings(), true);
Document dom = waitForProcessEnd(statusLocation1, 60);
// print(dom);
assertXpathExists("//wps:ProcessSucceeded", dom);
dom = waitForProcessEnd(statusLocation2, 60);
assertXpathExists("//wps:ProcessSucceeded", dom);
}
@Test
public void testInlineGetFeatureNameClash() throws Exception {
Assert.assertNotNull(getCatalog().getLayerByName("foo:PrimitiveGeoFeature"));
Assert.assertNotNull(getCatalog().getLayerByName("sf:PrimitiveGeoFeature"));
String request = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<wps:Execute version=\"1.0.0\" service=\"WPS\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.opengis.net/wps/1.0.0\" xmlns:wfs=\"http://www.opengis.net/wfs\" xmlns:wps=\"http://www.opengis.net/wps/1.0.0\" xmlns:ows=\"http://www.opengis.net/ows/1.1\" xmlns:gml=\"http://www.opengis.net/gml\" xmlns:ogc=\"http://www.opengis.net/ogc\" xmlns:wcs=\"http://www.opengis.net/wcs/1.1.1\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd\">\n" +
" <ows:Identifier>gs:Bounds</ows:Identifier>\n" +
" <wps:DataInputs>\n" +
" <wps:Input>\n" +
" <ows:Identifier>features</ows:Identifier>\n" +
" <wps:Reference mimeType=\"text/xml; subtype=wfs-collection/1.0\" xlink:href=\"http://geoserver/wfs\" method=\"POST\">\n" +
" <wps:Body>\n" +
" <wfs:GetFeature service=\"WFS\" version=\"1.0.0\" xmlns:foo='http://foo.org'>\n" +
" <wfs:Query typeName=\"foo:PrimitiveGeoFeature\"/>\n" +
" </wfs:GetFeature>\n" +
" </wps:Body>\n" +
" </wps:Reference>\n" +
" </wps:Input>\n" +
" </wps:DataInputs>\n" +
" <wps:ResponseForm>\n" +
" <wps:RawDataOutput>\n" +
" <ows:Identifier>bounds</ows:Identifier>\n" +
" </wps:RawDataOutput>\n" +
" </wps:ResponseForm>\n" +
"</wps:Execute>";
Document dom = postAsDOM(root(), request);
assertEquals("ows:BoundingBox", dom.getDocumentElement().getNodeName());
}
@Test
public void testChooseOutputSynchronous() throws Exception {
String xml =
"<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:MultiRaw</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>id</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1234</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='false'>" +
"<wps:Output>" +
"<ows:Identifier>${output}</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
// literal output
Document d = postAsDOM("wps", xml.replace("${output}", "literal"));
checkValidationErrors(d);
// print(d);
assertEquals("wps:ExecuteResponse", d.getDocumentElement().getNodeName());
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
assertXpathEvaluatesTo(
"1234",
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='literal']/wps:Data/wps:LiteralData",
d);
// text complex output
d = postAsDOM("wps", xml.replace("${output}", "text"));
// print(d);
checkValidationErrors(d);
assertEquals("wps:ExecuteResponse", d.getDocumentElement().getNodeName());
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
assertXpathEvaluatesTo(
"base64",
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='text']/wps:Data/wps:ComplexData/@encoding",
d);
String value = xp
.evaluate(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='text']/wps:Data/wps:ComplexData",
d);
assertEquals("This is the raw text", new String(Base64.decodeBase64(value)));
// binary complex output
d = postAsDOM("wps", xml.replace("${output}", "binary"));
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
assertXpathEvaluatesTo(
"base64",
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='binary']/wps:Data/wps:ComplexData/@encoding",
d);
value = xp
.evaluate(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='binary']/wps:Data/wps:ComplexData",
d);
assertArrayEquals(new byte[100], Base64.decodeBase64(value));
}
@Test
public void testRawFileExtension() throws Exception {
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' "
+ "xmlns:ows='http://www.opengis.net/ows/1.1'>"
+ "<ows:Identifier>gs:MultiRaw</ows:Identifier>"
+ "<wps:DataInputs>"
+ "<wps:Input>"
+ "<ows:Identifier>id</ows:Identifier>"
+ "<wps:Data>"
+ "<wps:LiteralData>1234</wps:LiteralData>"
+ "</wps:Data>"
+ "</wps:Input>"
+ "</wps:DataInputs>"
+ "<wps:ResponseForm>"
+ "<wps:ResponseDocument storeExecuteResponse='false'>"
+ "<wps:Output asReference=\"true\">"
+ "<ows:Identifier>${output}</ows:Identifier>"
+ "</wps:Output>"
+ "</wps:ResponseDocument>" + "</wps:ResponseForm>" + "</wps:Execute>";
// text complex output
Document d = postAsDOM("wps", xml.replace("${output}", "text"));
// print(d);
checkValidationErrors(d);
assertEquals("wps:ExecuteResponse", d.getDocumentElement().getNodeName());
// check we are using the RawData file extension
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
String reference = xp
.evaluate(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='text']/wps:Reference/@href",
d);
Map<String, Object> kvp = KvpUtils.parseQueryString(reference);
assertEquals("text.txt", kvp.get("outputId"));
}
@Test
public void testChooseOutputAsynchronous() throws Exception {
String xml =
"<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' " +
"xmlns:ows='http://www.opengis.net/ows/1.1'>" +
"<ows:Identifier>gs:MultiRaw</ows:Identifier>" +
"<wps:DataInputs>" +
"<wps:Input>" +
"<ows:Identifier>id</ows:Identifier>" +
"<wps:Data>" +
"<wps:LiteralData>1234</wps:LiteralData>" +
"</wps:Data>" +
"</wps:Input>" +
"</wps:DataInputs>" +
"<wps:ResponseForm>" +
"<wps:ResponseDocument storeExecuteResponse='true' status='true'>" +
"<wps:Output>" +
"<ows:Identifier>${output}</ows:Identifier>" +
"</wps:Output>" +
"</wps:ResponseDocument>" +
"</wps:ResponseForm>" +
"</wps:Execute>";
// literal output
Document d = submitAsynchronous(xml.replace("${output}", "literal"), 60);
checkValidationErrors(d);
// print(d);
assertEquals("wps:ExecuteResponse", d.getDocumentElement().getNodeName());
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
assertXpathEvaluatesTo(
"1234",
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='literal']/wps:Data/wps:LiteralData",
d);
// text complex output
d = submitAsynchronous(xml.replace("${output}", "text"), 60);
// print(d);
checkValidationErrors(d);
assertEquals("wps:ExecuteResponse", d.getDocumentElement().getNodeName());
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
assertXpathEvaluatesTo(
"base64",
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='text']/wps:Data/wps:ComplexData/@encoding",
d);
String value = xp
.evaluate(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='text']/wps:Data/wps:ComplexData",
d);
assertEquals("This is the raw text", new String(Base64.decodeBase64(value)));
// binary complex output
d = submitAsynchronous(xml.replace("${output}", "binary"), 60);
// print(d);
checkValidationErrors(d);
assertEquals( "wps:ExecuteResponse", d.getDocumentElement().getNodeName() );
assertXpathExists( "/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
assertXpathEvaluatesTo(
"base64",
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='binary']/wps:Data/wps:ComplexData/@encoding",
d);
value = xp
.evaluate(
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='binary']/wps:Data/wps:ComplexData",
d);
assertArrayEquals(new byte[100], Base64.decodeBase64(value));
}
@Test
public void testMultiOutputProcess() throws Exception {
String xml = "<wps:Execute service='WPS' version='1.0.0' xmlns:wfs='http://www.opengis.net/wfs' xmlns:wps='http://www.opengis.net/wps/1.0.0' xmlns:xlink='http://www.w3.org/1999/xlink' "
+ "xmlns:ows='http://www.opengis.net/ows/1.1'>"
+ "<ows:Identifier>gs:MultiOutputEcho</ows:Identifier>"
+ "<wps:DataInputs>"
+ "<wps:Input>"
+ "<ows:Identifier>text</ows:Identifier>"
+ "<wps:Reference mimeType='text/xml' xlink:href='http://geoserver/wps' method='POST'>"
+ "<wps:Body>"
+ "<wps:Execute service='WPS' version='1.0.0' xmlns:wps='http://www.opengis.net/wps/1.0.0' xmlns:ows='http://www.opengis.net/ows/1.1'>"
+ "<ows:Identifier>gs:MultiRaw</ows:Identifier>"
+ "<wps:DataInputs>"
+ "<wps:Input>"
+ "<ows:Identifier>id</ows:Identifier>"
+ "<wps:Data>"
+ "<wps:LiteralData>1234</wps:LiteralData>"
+ "</wps:Data>"
+ "</wps:Input>"
+ "</wps:DataInputs>"
+ "<wps:ResponseForm>"
+ "<wps:ResponseDocument storeExecuteResponse='true' status='true'>"
+ "<wps:Output>"
+ "<ows:Identifier>literal</ows:Identifier>"
+ "</wps:Output>"
+ "</wps:ResponseDocument>"
+ "</wps:ResponseForm>"
+ "</wps:Execute>"
+ "</wps:Body>"
+ "</wps:Reference>"
+ "</wps:Input>"
+ "</wps:DataInputs>"
+ "<wps:ResponseForm>"
+ "<wps:ResponseDocument>"
+ "<wps:Output>"
+ "<ows:Identifier>result</ows:Identifier>"
+ "</wps:Output>"
+ "</wps:ResponseDocument>"
+ "</wps:ResponseForm>"
+ "</wps:Execute>";
// Checks multi output result items by name.
// GEOS-6907:
// When a WPS task works with two concatenated WPS processes, if first of them returns more of one
// of output result items (e.g. sextante:kriging, gs:MultiRaw), then the next WPS process only gets
// the first item.
// The InternalWPSInputProvider class does not filter by name or data type to extract the correct
// output item.
Document d = postAsDOM( "wps", xml );
// print(d);
checkValidationErrors(d);
assertEquals("wps:ExecuteResponse", d.getDocumentElement().getNodeName());
assertXpathExists("/wps:ExecuteResponse/wps:Status/wps:ProcessSucceeded", d);
assertXpathEvaluatesTo("1", "count(//wps:Output)", d);
assertXpathEvaluatesTo(
"Echo='1234'",
"/wps:ExecuteResponse/wps:ProcessOutputs/wps:Output[ows:Identifier='result']/wps:Data/wps:LiteralData",
d);
}
private void assertProgress(String statusLocation, String progress) throws Exception {
Document dom = getAsDOM(statusLocation);
// print(dom);
assertXpathExists("//wps:ProcessStarted", dom);
assertXpathEvaluatesTo(progress, "//wps:ProcessStarted/@percentCompleted", dom);
}
private String submitMonkey(String id) throws Exception, XpathException {
String request = "wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&storeExecuteResponse=true&status=true&DataInputs=" + urlEncode("id=" + id);
Document dom = getAsDOM(request);
// print(dom);
return getStatusLocation(dom);
}
private String getStatusLocation(Document dom) throws XpathException {
assertXpathExists("//wps:ProcessAccepted", dom);
XpathEngine xpath = XMLUnit.newXpathEngine();
String fullStatusLocation = xpath.evaluate("//wps:ExecuteResponse/@statusLocation", dom);
String statusLocation = fullStatusLocation.substring(fullStatusLocation.indexOf('?') - 3);
return statusLocation;
}
private ListFeatureCollection collectionOfThings() {
SimpleFeatureType featureType = buildSampleFeatureType();
ListFeatureCollection fc = new ListFeatureCollection(featureType);
return fc;
}
private SimpleFeatureType buildSampleFeatureType() {
SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
tb.add("name", String.class);
tb.add("location", Point.class, DefaultGeographicCRS.WGS84);
tb.setName("thing");
SimpleFeatureType featureType = tb.buildFeatureType();
return featureType;
}
private ListFeatureCollection bombOutCollection() {
SimpleFeatureType featureType = buildSampleFeatureType();
ListFeatureCollection fc = new ListFeatureCollection(featureType) {
@Override
public SimpleFeatureIterator features() {
throw new RuntimeException("Toasted!");
}
@Override
protected Iterator openIterator() {
throw new RuntimeException("Toasted!");
}
};
return fc;
}
/**
* Checks the bounds process returned the expected envelope
* @param request
* @param id
*/
void executeState1BoundsTest(String request, String id) throws Exception {
if (!RemoteOWSTestSupport.isRemoteWMSStatesAvailable(LOGGER)) {
LOGGER.warning("Remote OWS tests disabled, skipping test with " + id + " reference source");
return;
}
MockHttpServletResponse resp = postAsServletResponse(root(), request);
ReferencedEnvelope re = toEnvelope(resp.getContentAsString());
Assert.assertEquals(-91.516129, re.getMinX(), 0.001);
Assert.assertEquals(36.986771, re.getMinY(), 0.001);
Assert.assertEquals(-87.507889, re.getMaxX(), 0.001);
Assert.assertEquals(42.509361, re.getMaxY(), 0.001);
}
ReferencedEnvelope toEnvelope(String xml) throws Exception {
Parser p = new Parser(new OWSConfiguration());
Object parsed = p.parse(new ByteArrayInputStream(xml.getBytes()));
Assert.assertTrue(parsed instanceof BoundingBoxType);
BoundingBoxType box = (BoundingBoxType) parsed;
ReferencedEnvelope re;
if(box.getCrs() != null) {
re = new ReferencedEnvelope(CRS.decode(box.getCrs()));
} else {
re = new ReferencedEnvelope();
}
re.expandToInclude((Double) box.getLowerCorner().get(0), (Double) box.getLowerCorner().get(1));
re.expandToInclude((Double) box.getUpperCorner().get(0), (Double) box.getUpperCorner().get(1));
return re;
}
String urlEncode(String string) throws Exception {
return URLEncoder.encode(string, "ASCII");
}
private void checkShapefileIntegrity(String[] typeNames, final InputStream in) throws IOException {
ZipInputStream zis = new ZipInputStream(in);
ZipEntry entry = null;
final String[] extensions = new String[] {".shp", ".shx", ".dbf", ".prj", ".cst"};
Set names = new HashSet();
for (String name : typeNames) {
for (String extension : extensions) {
names.add(name + extension);
}
}
while((entry = zis.getNextEntry()) != null) {
final String name = entry.getName();
Assert.assertTrue("Missing " + name, names.contains(name));
names.remove(name);
zis.closeEntry();
}
zis.close();
}
}