/* (c) 2014 -2016 Open Source Geospatial Foundation - all rights reserved
* 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.custommonkey.xmlunit.XMLAssert.assertXpathNotExists;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.net.URLEncoder;
import org.apache.commons.io.FileUtils;
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.wps.validator.MaxSizeValidator;
import org.geoserver.wps.validator.MultiplicityValidator;
import org.geoserver.wps.validator.NumberRangeValidator;
import org.geotools.data.DataUtilities;
import org.geotools.feature.NameImpl;
import org.geotools.process.geometry.GeometryProcessFactory;
import org.geotools.process.raster.RasterProcessFactory;
import org.geotools.util.NumberRange;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.w3c.dom.Document;
public class InputLimitsTest extends WPSTestSupport {
@Override
protected void setUpTestData(SystemTestData testData) throws Exception {
// need no layers for this test
testData.setUpSecurity();
}
@Before
public void setUpInternal() throws Exception {
// make extra sure we don't have anything else going
MonkeyProcess.clearCommands();
}
@Before
public void resetExecutionTimes() throws Exception {
WPSInfo wps = getGeoServer().getService(WPSInfo.class);
wps.setMaxSynchronousExecutionTime(0);
wps.setMaxAsynchronousExecutionTime(0);
wps.setMaxSynchronousTotalTime(0);
wps.setMaxAsynchronousTotalTime(0);
wps.setMaxAsynchronousProcesses(0);
wps.setMaxSynchronousProcesses(0);
getGeoServer().save(wps);
}
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
addWcs11Coverages(testData);
// add some limits to the processes
WPSInfo wps = getGeoServer().getService(WPSInfo.class);
// global size limits
wps.setMaxComplexInputSize(10);
// for the buffer process
ProcessGroupInfo geoGroup = new ProcessGroupInfoImpl();
geoGroup.setFactoryClass(GeometryProcessFactory.class);
geoGroup.setEnabled(true);
wps.getProcessGroups().add(geoGroup);
ProcessInfo buffer = new ProcessInfoImpl();
buffer.setEnabled(true);
buffer.setName(new NameImpl("geo", "buffer"));
buffer.getValidators().put("geom", new MaxSizeValidator(1));
buffer.getValidators().put("distance",
new NumberRangeValidator(new NumberRange<Double>(Double.class, 0d, 100d)));
buffer.getValidators().put("quadrantSegments",
new NumberRangeValidator(new NumberRange<Integer>(Integer.class, 2, 20)));
geoGroup.getFilteredProcesses().add(buffer);
// simplify process distance
ProcessInfo simplify = new ProcessInfoImpl();
simplify.setEnabled(true);
simplify.setName(new NameImpl("geo", "simplify"));
simplify.getValidators().put("distance",
new NumberRangeValidator(new NumberRange<Double>(Double.class, null, 100d)));
geoGroup.getFilteredProcesses().add(simplify);
// densify process
ProcessInfo densify = new ProcessInfoImpl();
densify.setEnabled(true);
densify.setName(new NameImpl("geo", "densify"));
densify.getValidators().put("distance",
new NumberRangeValidator(new NumberRange<Double>(Double.class, 0d, null)));
geoGroup.getFilteredProcesses().add(densify);
// for the contour process
ProcessGroupInfo rasterGroup = new ProcessGroupInfoImpl();
rasterGroup.setFactoryClass(RasterProcessFactory.class);
rasterGroup.setEnabled(true);
wps.getProcessGroups().add(rasterGroup);
ProcessInfo contour = new ProcessInfoImpl();
contour.setEnabled(true);
contour.setName(new NameImpl("ras", "Contour"));
contour.getValidators().put("data", new MaxSizeValidator(1));
contour.getValidators().put("levels",
new NumberRangeValidator(new NumberRange<Double>(Double.class, -8000d, 8000d)));
contour.getValidators().put("levels", new MultiplicityValidator(3));
rasterGroup.getFilteredProcesses().add(contour);
// save
getGeoServer().save(wps);
}
@Test
public void testDescribeBuffer() throws Exception {
Document d = getAsDOM(root() + "service=wps&request=describeprocess&identifier=geo:buffer");
// print(d);
// first off, let's check it's schema compliant
checkValidationErrors(d);
assertXpathExists("/wps:ProcessDescriptions", d);
String base = "/wps:ProcessDescriptions/ProcessDescription/DataInputs";
// first parameter, geometry
assertXpathExists(base + "/Input[1]", d);
assertXpathEvaluatesTo("geom", base + "/Input[1]/ows:Identifier", d);
assertXpathExists(base + "/Input[1]/ComplexData", d);
assertXpathEvaluatesTo("1", base + "/Input[1]/ComplexData/@maximumMegabytes", d);
// second parameter (float range)
assertXpathExists(base + "/Input[2]", d);
assertXpathEvaluatesTo("distance", base + "/Input[2]/ows:Identifier", d);
assertXpathExists(base + "/Input[2]/LiteralData", d);
assertXpathEvaluatesTo("closed", base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/@ows:rangeClosure", d);
assertXpathEvaluatesTo("0.0", base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/ows:MinimumValue", d);
assertXpathEvaluatesTo("100.0", base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/ows:MaximumValue", d);
// third parameter (integer range)
assertXpathExists(base + "/Input[3]", d);
assertXpathEvaluatesTo("quadrantSegments", base + "/Input[3]/ows:Identifier", d);
assertXpathExists(base + "/Input[3]/LiteralData", d);
assertXpathEvaluatesTo("closed", base
+ "/Input[3]/LiteralData/ows:AllowedValues/ows:Range/@ows:rangeClosure", d);
assertXpathEvaluatesTo("2", base
+ "/Input[3]/LiteralData/ows:AllowedValues/ows:Range/ows:MinimumValue", d);
assertXpathEvaluatesTo("20", base
+ "/Input[3]/LiteralData/ows:AllowedValues/ows:Range/ows:MaximumValue", d);
}
@Test
public void testDescribeSimplify() throws Exception {
Document d = getAsDOM(root()
+ "service=wps&request=describeprocess&identifier=geo:simplify");
// print(d);
// first off, let's check it's schema compliant
checkValidationErrors(d);
assertXpathExists("/wps:ProcessDescriptions", d);
String base = "/wps:ProcessDescriptions/ProcessDescription/DataInputs";
// first parameter, geometry
assertXpathExists(base + "/Input[1]", d);
assertXpathEvaluatesTo("geom", base + "/Input[1]/ows:Identifier", d);
assertXpathExists(base + "/Input[1]/ComplexData", d);
assertXpathEvaluatesTo("10", base + "/Input[1]/ComplexData/@maximumMegabytes", d);
// distance, half range
assertXpathExists(base + "/Input[2]", d);
assertXpathEvaluatesTo("distance", base + "/Input[2]/ows:Identifier", d);
assertXpathExists(base + "/Input[2]/LiteralData", d);
assertXpathEvaluatesTo("open-closed", base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/@ows:rangeClosure", d);
assertXpathNotExists(base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/ows:MinimumValue", d);
assertXpathEvaluatesTo("100.0", base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/ows:MaximumValue", d);
}
@Test
public void testDescribeDensify() throws Exception {
Document d = getAsDOM(root() + "service=wps&request=describeprocess&identifier=geo:densify");
// print(d);
// first off, let's check it's schema compliant
checkValidationErrors(d);
assertXpathExists("/wps:ProcessDescriptions", d);
String base = "/wps:ProcessDescriptions/ProcessDescription/DataInputs";
// first parameter, geometry
assertXpathExists(base + "/Input[1]", d);
assertXpathEvaluatesTo("geom", base + "/Input[1]/ows:Identifier", d);
assertXpathExists(base + "/Input[1]/ComplexData", d);
assertXpathEvaluatesTo("10", base + "/Input[1]/ComplexData/@maximumMegabytes", d);
// distance, half range
assertXpathExists(base + "/Input[2]", d);
assertXpathEvaluatesTo("distance", base + "/Input[2]/ows:Identifier", d);
assertXpathExists(base + "/Input[2]/LiteralData", d);
assertXpathEvaluatesTo("closed-open", base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/@ows:rangeClosure", d);
assertXpathEvaluatesTo("0.0", base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/ows:MinimumValue", d);
assertXpathNotExists(base
+ "/Input[2]/LiteralData/ows:AllowedValues/ows:Range/ows:MaximumValue", d);
}
@Test
public void testDescribeArea() throws Exception {
// this one has no custom limits, but there is the global limit for the complex input size
Document d = getAsDOM(root() + "service=wps&request=describeprocess&identifier=geo:area");
// print(d);
// first off, let's check it's schema compliant
checkValidationErrors(d);
assertXpathExists("/wps:ProcessDescriptions", d);
String base = "/wps:ProcessDescriptions/ProcessDescription/DataInputs";
// first parameter, geometry
assertXpathExists(base + "/Input[1]", d);
assertXpathEvaluatesTo("geom", base + "/Input[1]/ows:Identifier", d);
assertXpathExists(base + "/Input[1]/ComplexData", d);
assertXpathEvaluatesTo("10", base + "/Input[1]/ComplexData/@maximumMegabytes", d);
}
@Test
public void testDescribeContour() throws Exception {
// this one has no custom limits, but there is the global limit for the complex input size
Document d = getAsDOM(root() + "service=wps&request=describeprocess&identifier=ras:Contour");
// print(d);
// first off, let's check it's schema compliant
checkValidationErrors(d);
assertXpathExists("/wps:ProcessDescriptions", d);
String base = "/wps:ProcessDescriptions/ProcessDescription/DataInputs";
// first parameter, the raster
assertXpathExists(base + "/Input[1]", d);
assertXpathEvaluatesTo("data", base + "/Input[1]/ows:Identifier", d);
assertXpathExists(base + "/Input[1]/ComplexData", d);
assertXpathEvaluatesTo("1", base + "/Input[1]/ComplexData/@maximumMegabytes", d);
// the levels
assertXpathExists(base + "/Input[3]", d);
assertXpathEvaluatesTo("levels", base + "/Input[3]/ows:Identifier", d);
assertXpathEvaluatesTo("0", base + "/Input[3]/@minOccurs", d);
assertXpathEvaluatesTo("3", base + "/Input[3]/@maxOccurs", d);
assertXpathExists(base + "/Input[3]/LiteralData", d);
assertXpathEvaluatesTo("closed", base
+ "/Input[3]/LiteralData/ows:AllowedValues/ows:Range/@ows:rangeClosure", d);
assertXpathEvaluatesTo("-8000.0", base
+ "/Input[3]/LiteralData/ows:AllowedValues/ows:Range/ows:MinimumValue", d);
assertXpathEvaluatesTo("8000.0", base
+ "/Input[3]/LiteralData/ows:AllowedValues/ows:Range/ows:MaximumValue", d);
// first parameter, the roid geometry
assertXpathExists(base + "/Input[7]", d);
assertXpathEvaluatesTo("roi", base + "/Input[7]/ows:Identifier", d);
assertXpathExists(base + "/Input[7]/ComplexData", d);
assertXpathEvaluatesTo("10", base + "/Input[7]/ComplexData/@maximumMegabytes", d);
}
@Test
public void testBufferLargeInlineGeometry() throws Exception {
String wkt = buildLineString((Short.MAX_VALUE + 1) * 2 + 1);
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>geo: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["
+ wkt
+ "]]>"
+ "</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>";
Document dom = postAsDOM("wps", xml);
// print(dom);
assertXpathExists("//wps:Status/wps:ProcessFailed", dom);
assertXpathEvaluatesTo("geom",
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/@locator", dom);
String message = xp
.evaluate(
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/ows:ExceptionText",
dom);
assertTrue(message.contains("exceeds the maximum allowed"));
assertTrue(message.contains("geom"));
}
@Test
public void testBufferLargeFileReferenceGeometry() throws Exception {
// write the large string to a file
String wkt = buildLineString((Short.MAX_VALUE + 10000) * 2);
File tmp = getResourceLoader().find("tmp");
File wktDataFile = new File(tmp, "line.wkt");
FileUtils.writeStringToFile(wktDataFile, wkt);
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>geo: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:Reference mimeType=\"application/wkt\" "
+ "xlink:href=\""
+ DataUtilities.fileToURL(wktDataFile)
+ "\"/>\n"
+ "</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>";
FileUtils.writeStringToFile(new File("/tmp/request.xml"), xml);
Document dom = postAsDOM("wps", xml);
// print(dom);
assertXpathExists("//wps:Status/wps:ProcessFailed", dom);
assertXpathEvaluatesTo("geom",
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/@locator", dom);
String message = xp
.evaluate(
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/ows:ExceptionText",
dom);
assertTrue(message.contains("exceeds maximum allowed size"));
assertTrue(message.contains("geom"));
}
@Test
public void testBufferLargeDistance() throws Exception {
String wkt = buildLineString(10);
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>geo:buffer</ows:Identifier>"
+ "<wps:DataInputs>"
+ "<wps:Input>"
+ "<ows:Identifier>distance</ows:Identifier>"
+ "<wps:Data>"
+ "<wps:LiteralData>200</wps:LiteralData>"
+ "</wps:Data>"
+ "</wps:Input>"
+ "<wps:Input>"
+ "<ows:Identifier>geom</ows:Identifier>"
+ "<wps:Data>"
+ "<wps:ComplexData mimeType=\"application/wkt\">"
+ "<![CDATA["
+ wkt
+ "]]>"
+ "</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>";
Document dom = postAsDOM("wps", xml);
// print(dom);
assertXpathExists("//wps:Status/wps:ProcessFailed", dom);
assertXpathEvaluatesTo("distance",
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/@locator", dom);
String message = xp
.evaluate(
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/ows:ExceptionText",
dom);
assertTrue(message.contains("distance"));
assertTrue(message.contains("Value 200.0 is out of the valid range [0.0, 100.0]"));
}
private String buildLineString(int coordinateCount) {
// generate a geometry that's more than 1MB worth of data (according to the estimator)
StringBuilder sb = new StringBuilder("LINESTRING(");
for (int i = 0; i < coordinateCount; i++) {
sb.append(i).append(" ").append(i);
if (i < coordinateCount - 1) {
sb.append(", ");
}
}
sb.append(")");
String wkt = sb.toString();
return wkt;
}
@Test
public void testCountourTooManyLevels() throws Exception {
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>ras:Contour</ows:Identifier>\n"
+ " <wps:DataInputs>\n"
+ " <wps:Input>\n"
+ " <ows:Identifier>data</ows:Identifier>\n"
+ " <wps:Reference mimeType=\"image/tiff\" xlink:href=\"http://geoserver/wcs\" method=\"POST\">\n"
+ " <wps:Body>\n"
+ " <wcs:GetCoverage service=\"WCS\" version=\"1.1.1\">\n"
+ " <ows:Identifier>"
+ getLayerId(MockData.TASMANIA_DEM)
+ "</ows:Identifier>\n"
+ " <wcs:DomainSubset>\n"
+ " <gml:BoundingBox crs=\"http://www.opengis.net/gml/srs/epsg.xml#4326\">\n"
+ " <ows:LowerCorner>-180 -90</ows:LowerCorner>\n"
+ " <ows:UpperCorner>180 90</ows:UpperCorner>\n"
+ " </gml:BoundingBox>\n"
+ " </wcs:DomainSubset>\n"
+ " <wcs:Output format=\"image/tiff\"/>\n"
+ " </wcs:GetCoverage>\n"
+ " </wps:Body>\n"
+ " </wps:Reference>\n"
+ " </wps:Input>\n"
+ " <wps:Input>\n"
+ " <ows:Identifier>levels</ows:Identifier>\n"
+ " <wps:Data>\n"
+ " <wps:LiteralData>0</wps:LiteralData>\n"
+ " </wps:Data>\n"
+ " </wps:Input>\n"
+ " <wps:Input>\n"
+ " <ows:Identifier>levels</ows:Identifier>\n"
+ " <wps:Data>\n"
+ " <wps:LiteralData>10</wps:LiteralData>\n"
+ " </wps:Data>\n"
+ " </wps:Input>\n"
+ " <wps:Input>\n"
+ " <ows:Identifier>levels</ows:Identifier>\n"
+ " <wps:Data>\n"
+ " <wps:LiteralData>20</wps:LiteralData>\n"
+ " </wps:Data>\n"
+ " </wps:Input>\n"
+ " <wps:Input>\n"
+ " <ows:Identifier>levels</ows:Identifier>\n"
+ " <wps:Data>\n"
+ " <wps:LiteralData>30</wps:LiteralData>\n"
+ " </wps:Data>\n"
+ " </wps:Input>\n"
+ " </wps:DataInputs>\n"
+ " <wps:ResponseForm>\n"
+ " <wps:RawDataOutput mimeType=\"text/xml; subtype=wfs-collection/1.0\">\n"
+ " <ows:Identifier>result</ows:Identifier>\n"
+ " </wps:RawDataOutput>\n"
+ " </wps:ResponseForm>\n" + "</wps:Execute>";
Document dom = postAsDOM("wps", xml);
// print(dom);
assertXpathExists("//wps:Status/wps:ProcessFailed", dom);
assertXpathExists("//wps:Status/wps:ProcessFailed", dom);
assertXpathEvaluatesTo("levels",
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/@locator", dom);
String message = xp
.evaluate(
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/ows:ExceptionText",
dom);
assertTrue(message.contains("levels"));
assertTrue(message.contains("Too many values"));
}
@Test
public void testCountourLevelsOutOfRange() throws Exception {
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>ras:Contour</ows:Identifier>\n"
+ " <wps:DataInputs>\n"
+ " <wps:Input>\n"
+ " <ows:Identifier>data</ows:Identifier>\n"
+ " <wps:Reference mimeType=\"image/tiff\" xlink:href=\"http://geoserver/wcs\" method=\"POST\">\n"
+ " <wps:Body>\n"
+ " <wcs:GetCoverage service=\"WCS\" version=\"1.1.1\">\n"
+ " <ows:Identifier>"
+ getLayerId(MockData.TASMANIA_DEM)
+ "</ows:Identifier>\n"
+ " <wcs:DomainSubset>\n"
+ " <gml:BoundingBox crs=\"http://www.opengis.net/gml/srs/epsg.xml#4326\">\n"
+ " <ows:LowerCorner>-180 -90</ows:LowerCorner>\n"
+ " <ows:UpperCorner>180 90</ows:UpperCorner>\n"
+ " </gml:BoundingBox>\n"
+ " </wcs:DomainSubset>\n"
+ " <wcs:Output format=\"image/tiff\"/>\n"
+ " </wcs:GetCoverage>\n"
+ " </wps:Body>\n"
+ " </wps:Reference>\n"
+ " </wps:Input>\n"
+ " <wps:Input>\n"
+ " <ows:Identifier>levels</ows:Identifier>\n"
+ " <wps:Data>\n"
+ " <wps:LiteralData>10000</wps:LiteralData>\n"
+ " </wps:Data>\n"
+ " </wps:Input>\n"
+ " </wps:DataInputs>\n"
+ " <wps:ResponseForm>\n"
+ " <wps:RawDataOutput mimeType=\"text/xml; subtype=wfs-collection/1.0\">\n"
+ " <ows:Identifier>result</ows:Identifier>\n"
+ " </wps:RawDataOutput>\n"
+ " </wps:ResponseForm>\n" + "</wps:Execute>";
Document dom = postAsDOM("wps", xml);
// print(dom);
assertXpathExists("//wps:Status/wps:ProcessFailed", dom);
assertXpathExists("//wps:Status/wps:ProcessFailed", dom);
assertXpathEvaluatesTo("levels",
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/@locator", dom);
String message = xp
.evaluate(
"//wps:Status/wps:ProcessFailed/ows:ExceptionReport/ows:Exception/ows:ExceptionText",
dom);
assertTrue(message.contains("levels"));
assertTrue(message.contains(" Value 10000.0 is out of the valid range [-8000.0, 8000.0]"));
}
@Test
@Ignore // see [GEOS-7835] WPS execution time limits test randomly breaks builds
public void testAsyncExecutionLimit() throws Exception {
// set synchronous process limits
WPSInfo wps = getGeoServer().getService(WPSInfo.class);
wps.setMaxAsynchronousExecutionTime(2);
wps.setMaxAsynchronousTotalTime(3);
getGeoServer().save(wps);
// submit an asynchronous request which will take longer than the execution time limit to run
String statusLocation = submitAsynchronousRequest(
"wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&storeExecuteResponse=true&status=true&DataInputs="
+ urlEncode("id=x1"));
waitForProcessStart(statusLocation, 10);
MonkeyProcess.wait("x1", 2500);
MonkeyProcess.progress("x1", 54f, false);
// request should fail exceeding asynchronous execution time limit
Document response3 = waitForProcessEnd(statusLocation, 10);
assertXpathExists(
"//ows:ExceptionText[contains(., 'maxExecutionTime 2 seconds, maxTotalTime 3 seconds')]",
response3);
}
@Test
@Ignore // see [GEOS-7835] WPS execution time limits test randomly breaks builds
public void testAsyncTotalLimit() throws Exception {
// set synchronous process limits
WPSInfo wps = getGeoServer().getService(WPSInfo.class);
wps.setMaxAsynchronousExecutionTime(2);
wps.setMaxAsynchronousTotalTime(3);
wps.setMaxAsynchronousProcesses(1); // queue requests
getGeoServer().save(wps);
// submit 3 asynchronous requests each running within the execution time limit but the last one
// exceeding the total time limit when run one after another
String statusLocationX1 = submitAsynchronousRequest(
"wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&storeExecuteResponse=true&status=true&DataInputs="
+ urlEncode("id=x1"));
String statusLocationX2 = submitAsynchronousRequest(
"wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&storeExecuteResponse=true&status=true&DataInputs="
+ urlEncode("id=x2"));
String statusLocationX3 = submitAsynchronousRequest(
"wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&storeExecuteResponse=true&status=true&DataInputs="
+ urlEncode("id=x3"));
MonkeyProcess.wait("x1", 1100);
MonkeyProcess.wait("x2", 1100);
MonkeyProcess.wait("x3", 1100);
MonkeyProcess.exit("x1", null, false);
MonkeyProcess.exit("x2", null, false);
MonkeyProcess.progress("x3", 54f, false);
// First request should succeed
Document response1 = waitForProcessEnd(statusLocationX1, 10);
assertXpathExists("//wps:ProcessSucceeded", response1);
// Second request should succeed
Document response2 = waitForProcessEnd(statusLocationX2, 10);
assertXpathExists("//wps:ProcessSucceeded", response2);
// Third request should fail as it exceeds the asynchronous total time limit
Document response3 = waitForProcessEnd(statusLocationX3, 10);
assertXpathExists(
"//ows:ExceptionText[contains(., 'maxExecutionTime 2 seconds, maxTotalTime 3 seconds')]",
response3);
}
@Test
@Ignore // see [GEOS-7835] WPS execution time limits test randomly breaks builds
public void testSyncExecutionLimits() throws Exception {
// set synchronous process limits
WPSInfo wps = getGeoServer().getService(WPSInfo.class);
wps.setMaxSynchronousExecutionTime(1);
wps.setMaxSynchronousTotalTime(2);
getGeoServer().save(wps);
// set process called to wait for longer than maximum execution timeout and then update progress
MonkeyProcess.wait("x1", 1100);
MonkeyProcess.progress("x1", 54f, false);
// run the process and get the result
Document result = getAsDOM("wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&DataInputs="
+ urlEncode("id=x1"));
// request should have failed as it exceeds the synchronous execution time limit
assertXpathExists(
"//ows:ExceptionText[contains(., 'maxExecutionTime 1 seconds, maxTotalTime 2 seconds')]",
result);
}
@Test
public void testSyncTotalLimit() throws Exception {
// set synchronous process limits
WPSInfo wps = getGeoServer().getService(WPSInfo.class);
wps.setMaxSynchronousTotalTime(1);
getGeoServer().save(wps);
// set process called to wait for longer than maximum queue and execution timeout and then update progress
MonkeyProcess.wait("x1", 1100);
MonkeyProcess.progress("x1", 54f, false);
// run the process and get the result
Document result = getAsDOM("wps?service=WPS&version=1.0.0&request=Execute&Identifier=gs:Monkey&DataInputs="
+ urlEncode("id=x1"));
// request should have failed as it exceeds the synchronous total time limit
assertXpathExists(
"//ows:ExceptionText[contains(., 'maxTotalTime 1 seconds')]",
result);
}
String urlEncode(String string) throws Exception {
return URLEncoder.encode(string, "ASCII");
}
private String submitAsynchronousRequest(String request)
throws Exception {
Document response = getAsDOM(request);
return getStatusLocation(response);
}
private String getStatusLocation(Document dom) throws XpathException {
XpathEngine xpath = XMLUnit.newXpathEngine();
String fullStatusLocation = xpath.evaluate("//wps:ExecuteResponse/@statusLocation", dom);
return fullStatusLocation.substring(fullStatusLocation.indexOf('?') - 3);
}
}