/* (c) 2014 - 2017 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2014 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.wms_1_3;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.namespace.QName;
import org.apache.commons.io.FileUtils;
import org.custommonkey.xmlunit.NamespaceContext;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.eclipse.xsd.XSDSchema;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.data.test.SystemTestData.LayerProperty;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSInfo;
import org.geoserver.wms.WMSTestSupport;
import org.geoserver.wms.featureinfo.GML3FeatureInfoOutputFormat;
import org.geoserver.wms.featureinfo.GetFeatureInfoKvpReader;
import org.geoserver.wms.featureinfo.GetFeatureInfoOutputFormat;
import org.geoserver.wms.featureinfo.TextFeatureInfoOutputFormat;
import org.geoserver.wms.featureinfo.XML311FeatureInfoOutputFormat;
import org.geoserver.wms.wms_1_1_1.CapabilitiesTest;
import org.geotools.filter.v1_1.OGC;
import org.geotools.util.logging.Logging;
import org.junit.Test;
import org.w3c.dom.Document;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;
/**
* A GetFeatureInfo 1.3.0 integration test suite covering both spec mandates and geoserver specific
* features.
*/
public class GetFeatureInfoIntegrationTest extends WMSTestSupport {
public static String WCS_PREFIX = "wcs";
public static String WCS_URI = "http://www.opengis.net/wcs/1.1.1";
public static QName TASMANIA_BM = new QName(WCS_URI, "BlueMarble", WCS_PREFIX);
public static QName SQUARES = new QName(MockData.CITE_URI, "squares", MockData.CITE_PREFIX);
public static QName SAMPLEGRIB = new QName(WCS_URI, "sampleGrib", WCS_PREFIX);
public static QName GENERIC_LINES = new QName(MockData.DEFAULT_URI, "genericLines", MockData.DEFAULT_PREFIX);
public static QName STATES = new QName(MockData.SF_URI, "states", MockData.SF_PREFIX);
@Override
protected void setUpTestData(SystemTestData testData) throws Exception {
super.setUpTestData(testData);
testData.setUpWcs10RasterLayers();
}
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
Map<String, String> namespaces = new HashMap<String, String>();
namespaces.put("xlink", "http://www.w3.org/1999/xlink");
namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance");
namespaces.put("wms", "http://www.opengis.net/wms");
namespaces.put("ows", "http://www.opengis.net/ows");
namespaces.put("ogc", "http://www.opengis.net/ogc");
namespaces.put("wfs", "http://www.opengis.net/wfs");
namespaces.put("gml", "http://www.opengis.net/gml");
namespaces.put(WCS_PREFIX, WCS_URI);
NamespaceContext ctx = new SimpleNamespaceContext(namespaces);
XMLUnit.setXpathNamespaceContext(ctx);
Logging.getLogger("org.geoserver.ows").setLevel(Level.OFF);
WMSInfo wmsInfo = getGeoServer().getService(WMSInfo.class);
wmsInfo.setMaxBuffer(50);
getGeoServer().save(wmsInfo);
Catalog catalog = getCatalog();
testData.addStyle("thickStroke","thickStroke.sld",CapabilitiesTest.class,catalog);
testData.addStyle("raster","raster.sld",CapabilitiesTest.class,catalog);
testData.addStyle("rasterScales","rasterScales.sld",CapabilitiesTest.class,catalog);
testData.addStyle("squares","squares.sld",CapabilitiesTest.class,catalog);
testData.addStyle("forestsManyRules", "ForestsManyRules.sld", CapabilitiesTest.class, catalog);
testData.addVectorLayer(SQUARES,Collections.EMPTY_MAP,"squares.properties",
CapabilitiesTest.class,catalog);
Map propertyMap = new HashMap();
propertyMap.put(LayerProperty.STYLE,"raster");
testData.addRasterLayer(TASMANIA_BM, "tazbm.tiff","tiff",propertyMap,
SystemTestData.class,catalog);
testData.addRasterLayer(SAMPLEGRIB, "sampleGrib.tif", null, propertyMap,
GetFeatureInfoIntegrationTest.class, catalog);
// this data set contain lines strings but with geometry type set as geometry
testData.addVectorLayer(GENERIC_LINES, Collections.emptyMap(), "genericLines.properties", getClass(), getCatalog());
testData.addStyle("genericLinesStyle", "genericLines.sld", getClass(), getCatalog());
// set up a non-querable layer.
testData.addStyle("Population", "Population.sld", CapabilitiesTest.class, catalog);
testData.addVectorLayer(STATES, Collections.emptyMap(), "states.properties", CapabilitiesTest.class, catalog);
LayerInfo layer = catalog.getLayerByName(getLayerId(STATES));
layer.setQueryable(false);
catalog.save(layer);
}
// @Override
// protected void setUpInternal() throws Exception {
// super.setUpInternal();
//
// Map<String, String> namespaces = new HashMap<String, String>();
// namespaces.put("xlink", "http://www.w3.org/1999/xlink");
// namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance");
// namespaces.put("wms", "http://www.opengis.net/wms");
// namespaces.put("ows", "http://www.opengis.net/ows");
// namespaces.put("ogc", "http://www.opengis.net/ogc");
// namespaces.put("wfs", "http://www.opengis.net/wfs");
// namespaces.put("gml", "http://www.opengis.net/gml");
// namespaces.put(WCS_PREFIX, WCS_URI);
//
// NamespaceContext ctx = new SimpleNamespaceContext(namespaces);
// XMLUnit.setXpathNamespaceContext(ctx);
//
// Logging.getLogger("org.geoserver.ows").setLevel(Level.OFF);
// WMSInfo wmsInfo = getGeoServer().getService(WMSInfo.class);
// wmsInfo.setMaxBuffer(50);
// getGeoServer().save(wmsInfo);
// }
// @Override
// protected void populateDataDirectory(MockData dataDirectory) throws Exception {
// super.populateDataDirectory(dataDirectory);
// dataDirectory.addWcs10Coverages();
// dataDirectory.addStyle("thickStroke", getClass()
// .getResource("../wms_1_1_1/thickStroke.sld"));
// dataDirectory.addStyle("raster", getClass().getResource("../wms_1_1_1/raster.sld"));
// dataDirectory.addStyle("rasterScales",
// getClass().getResource("../wms_1_1_1/rasterScales.sld"));
// dataDirectory.addCoverage(TASMANIA_BM, getClass().getResource("../wms_1_1_1/tazbm.tiff"),
// "tiff", "raster");
// dataDirectory.addStyle("squares", getClass().getResource("../wms_1_1_1/squares.sld"));
// dataDirectory.addPropertiesType(SQUARES,
// getClass().getResource("../wms_1_1_1/squares.properties"), null);
// }
/**
* As per section 7.4.1, a client shall not issue a GetFeatureInfo request for non queryable
* layers; yet that section is not too clear with regard to whether an exception should be
* thrown. I read it like an exception with OperationNotSupported code should be thrown. The
* full text is:
* <p>
* <i> GetFeatureInfo is an optional operation. It is only supported for those Layers for which
* the attribute queryable="1" (true) has been defined or inherited. A client shall not issue a
* GetFeatureInfo request for other layers. A WMS shall respond with a properly formatted
* service exception (XML) response (code = OperationNotSupported) if it receives a
* GetFeatureInfo request but does not support it. </i>
* </p>
*/
@Test
public void testQueryNonQueryableLayer() throws Exception {
// HACK: fake the WMS facade to inform the layer is non queryable. Looks like we would need
// a LayerInfo.isQueryable() property
final WMS wms = (WMS) applicationContext.getBean("wms");
GetFeatureInfoKvpReader reader = (GetFeatureInfoKvpReader) applicationContext
.getBean("getFeatureInfoKvpReader");
try {
WMS fakeWMS = new WMS(wms.getGeoServer()) {
@Override
public boolean isQueryable(LayerInfo layer) {
if ("Forests".equals(layer.getName())) {
return false;
}
return super.isQueryable(layer);
}
};
reader.setWMS(fakeWMS);
String layer = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
Document doc = dom(get(request), true);
XMLAssert.assertXpathEvaluatesTo("LayerNotQueryable",
"/ogc:ServiceExceptionReport/ogc:ServiceException/@code", doc);
} finally {
// restore the original wms
reader.setWMS(wms);
}
}
/**
* As for section 7.4.3.7, a missing or incorrectly specified pair of I,J parameters shall issue
* a service exception with {@code InvalidPoint} code.
*
*/
@Test
public void testInvalidPoint() throws Exception {
String layer = MockData.FORESTS.getPrefix() + ":" + MockData.FORESTS.getLocalPart();
// missing I,J parameters
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20";
Document doc = dom(get(request), true);
// print(doc);
XMLAssert.assertXpathEvaluatesTo("InvalidPoint",
"/ogc:ServiceExceptionReport/ogc:ServiceException/@code", doc);
// invalid I,J parameters
request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=A&j=";
doc = dom(get(request), true);
// print(doc);
XMLAssert.assertXpathEvaluatesTo("InvalidPoint",
"/ogc:ServiceExceptionReport/ogc:ServiceException/@code", doc);
}
/**
* Tests a simple GetFeatureInfo works, and that the result contains the expected polygon
*
*/
@Test
public void testSimple() throws Exception {
String layer = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
String result = getAsString(request);
// System.out.println(result);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
}
@Test
public void testAllowedMimeTypes() throws Exception {
WMSInfo wms = getWMS().getServiceInfo();
GetFeatureInfoOutputFormat format = new TextFeatureInfoOutputFormat(getWMS());
wms.getGetFeatureInfoMimeTypes().add(format.getContentType());
wms.setGetFeatureInfoMimeTypeCheckingEnabled(true);
getGeoServer().save(wms);
// check mime type allowed
String layer = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
String result = getAsString(request);
// System.out.println(result);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
// check mime type not allowed
request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format="+GML3FeatureInfoOutputFormat.FORMAT+"&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
result = getAsString(request);
assertTrue(result.indexOf("ForbiddenFormat") > 0);
wms.getGetFeatureInfoMimeTypes().clear();
wms.setGetFeatureInfoMimeTypeCheckingEnabled(false);
getGeoServer().save(wms);
request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format="+GML3FeatureInfoOutputFormat.FORMAT+"&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
result = getAsString(request);
assertTrue(result.indexOf("Green Forest") > 0);
// GML 3.1.1 as text/xml; subtype=gml/3.1.1
request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=" +
XML311FeatureInfoOutputFormat.FORMAT + "&request=GetFeatureInfo&layers=" + layer +
"&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
result = getAsString(request);
assertTrue(result.indexOf("Green Forest") > 0);
}
@Test
public void testCustomTemplateManyRules() throws Exception {
// setup custom template
File root = getTestData().getDataDirectoryRoot();
File target = new File(root, "workspaces/" + MockData.FORESTS.getPrefix() + "/content.ftl");
File source = new File("./src/test/resources/org/geoserver/wms/content.ftl");
try {
assertTrue(source.exists());
FileUtils.copyFile(source, target);
// request with default style, just one rule
String layer = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
Document dom = getAsDOM(request);
// print(dom);
XMLAssert.assertXpathExists("/html/body/ul/li/b[text() = 'Type: Forests']", dom);
// request with a style having 21 rules, used to fail, see GEOS-5534
request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=forestsManyRules&format=jpeg&info_format=text/html&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
dom = getAsDOM(request);
// print(dom);
XMLAssert.assertXpathExists("/html/body/ul/li/b[text() = 'Type: Forests']", dom);
} finally {
FileUtils.deleteQuietly(target);
}
}
/**
* Tests a simple GetFeatureInfo works, and that the result contains the expected polygon
*
*/
@Test
public void testSimpleHtml() throws Exception {
String layer = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
Document dom = getAsDOM(request);
// print(dom);
// count lines that do contain a forest reference
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[starts-with(.,'Forests.')])", dom);
}
/**
* Tests GetFeatureInfo with a buffer specified works, and that the result contains the expected
* polygon
*
*/
@Test
public void testBuffer() throws Exception {
// to setup the request and the buffer I rendered BASIC_POLYGONS using GeoServer, then
// played
// against the image coordinates
String layer = getLayerId(MockData.BASIC_POLYGONS);
String base = "wms?version=1.3.0&bbox=-4.5,-2.,4.5,7&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=300&height=300";
Document dom = getAsDOM(base + "&i=85&j=230");
// make sure the document is empty, as we chose an area with no features inside
XMLAssert.assertXpathEvaluatesTo("0", "count(/html/body/table/tr)", dom);
// another request that will catch one feature due to the extended buffer, make sure it's in
dom = getAsDOM(base + "&i=85&j=230&buffer=40");
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[starts-with(.,'BasicPolygons.')])", dom);
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[. = 'BasicPolygons.1107531493630'])", dom);
// this one would end up catching everything (3 features) if it wasn't that we say the max
// buffer at 50
// in the WMS configuration
dom = getAsDOM(base + "&i=85&j=230&buffer=300");
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[starts-with(.,'BasicPolygons.')])", dom);
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[. = 'BasicPolygons.1107531493630'])", dom);
}
/**
* Tests GetFeatureInfo with a buffer specified works, and that the result contains the expected
* polygon
*
*/
@Test
public void testAutoBuffer() throws Exception {
String layer = getLayerId(MockData.BASIC_POLYGONS);
String base = "wms?version=1.3.0&bbox=-4.5,-2.,4.5,7&format=jpeg&info_format=text/html&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=300&height=300&i=111&j=229";
Document dom = getAsDOM(base + "&styles=");
// make sure the document is empty, the style we chose has thin lines
XMLAssert.assertXpathEvaluatesTo("0", "count(/html/body/table/tr)", dom);
// another request that will catch one feature due to the style with a thick stroke, make
// sure it's in
dom = getAsDOM(base + "&styles=thickStroke");
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[starts-with(.,'BasicPolygons.')])", dom);
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[. = 'BasicPolygons.1107531493630'])", dom);
}
/**
* Tests GetFeatureInfo with a buffer specified works, and that the result contains the expected
* polygon
*
*/
@Test
public void testBufferScales() throws Exception {
String layer = getLayerId(SQUARES);
String base = "wms?version=1.3.0&&format=png&info_format=text/html&request=GetFeatureInfo&layers="
+ layer
+ "&query_layers="
+ layer
+ "&styles=squares&bbox=0,0,10000,10000&feature_count=10&srs=EPSG:32632";
// first request, should provide no result, scale is 1:100
int w = (int) (100.0 / 0.28 * 1000); // dpi compensation
Document dom = getAsDOM(featureInfoRequest(base, w));
// print(dom);
// make sure the document is empty, the style we chose has thin lines
XMLAssert.assertXpathEvaluatesTo("0", "count(/html/body/table/tr)", dom);
// second request, should provide oe result, scale is 1:50
w = (int) (200.0 / 0.28 * 1000); // dpi compensation
dom = getAsDOM(featureInfoRequest(base, w));
// print(dom);
XMLAssert.assertXpathEvaluatesTo("1",
"count(/html/body/table/tr/td[starts-with(.,'squares.')])", dom);
XMLAssert
.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/td[. = 'squares.1'])", dom);
// third request, should provide two result, scale is 1:10
w = (int) (1000.0 / 0.28 * 1000); // dpi compensation
dom = getAsDOM(featureInfoRequest(base, w));
// print(dom);
XMLAssert.assertXpathEvaluatesTo("2",
"count(/html/body/table/tr/td[starts-with(.,'squares.')])", dom);
XMLAssert
.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/td[. = 'squares.1'])", dom);
XMLAssert
.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/td[. = 'squares.2'])", dom);
}
private String featureInfoRequest(String base, int w) {
String request = base + "&width=" + w + "&height=" + w + "&i=20&j=" + (w - 20);
return request;
}
/**
* Tests a GetFeatureInfo againworks, and that the result contains the expected polygon
*
*/
@Test
public void testTwoLayers() throws Exception {
String layer = getLayerId(MockData.FORESTS) + "," + getLayerId(MockData.LAKES);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10&info";
String result = getAsString(request);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
// GEOS-2603 GetFeatureInfo returns html tables without css style if more than one layer is
// selected
assertTrue(result.indexOf("<style type=\"text/css\">") > 0);
}
/**
* Check GetFeatureInfo returns an error if the format is not known, instead of returning the
* text format as in https://osgeo-org.atlassian.net/browse/GEOS-1924
*
*/
@Test
public void testUknownFormat() throws Exception {
String layer = MockData.FORESTS.getPrefix() + ":" + MockData.FORESTS.getLocalPart();
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=unknown/format&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
Document doc = dom(get(request), true);
// print(doc);
XMLAssert.assertXpathEvaluatesTo("1",
"count(//ogc:ServiceExceptionReport/ogc:ServiceException)", doc);
XMLAssert.assertXpathEvaluatesTo("InvalidFormat",
"/ogc:ServiceExceptionReport/ogc:ServiceException/@code", doc);
XMLAssert.assertXpathEvaluatesTo("info_format",
"/ogc:ServiceExceptionReport/ogc:ServiceException/@locator", doc);
}
@Test
public void testCoverage() throws Exception {
// https://osgeo-org.atlassian.net/browse/GEOS-2574
String layer = getLayerId(TASMANIA_BM);
String request = "wms?version=1.3.0&service=wms&request=GetFeatureInfo" + "&layers="
+ layer + "&styles=&bbox=-44.5,146.5,-43,148&width=600&height=600"
+ "&info_format=text/html&query_layers=" + layer + "&i=300&j=300&srs=EPSG:4326";
Document dom = getAsDOM(request);
print(dom);
// we also have the charset which may be platf. dep.
XMLAssert.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/th[. = 'RED_BAND'])", dom);
XMLAssert.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/th[. = 'GREEN_BAND'])",
dom);
XMLAssert
.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/th[. = 'BLUE_BAND'])", dom);
}
@Test
public void testCoverageGML() throws Exception {
// https://osgeo-org.atlassian.net/browse/GEOS-3996
String layer = getLayerId(TASMANIA_BM);
String request = "wms?version=1.3.0&service=wms&request=GetFeatureInfo" + "&layers="
+ layer + "&styles=&bbox=-44.5,146.5,-43,148&width=600&height=600"
+ "&info_format=application/vnd.ogc.gml&query_layers=" + layer
+ "&i=300&j=300&srs=EPSG:4326";
Document dom = getAsDOM(request);
// print(dom);
XMLAssert.assertXpathEvaluatesTo("26.0",
"//wfs:FeatureCollection/gml:featureMember/wcs:BlueMarble/wcs:RED_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("70.0",
"//wfs:FeatureCollection/gml:featureMember/wcs:BlueMarble/wcs:GREEN_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("126.0",
"//wfs:FeatureCollection/gml:featureMember/wcs:BlueMarble/wcs:BLUE_BAND", dom);
}
@Test
public void testCoverageGML31() throws Exception {
// https://osgeo-org.atlassian.net/browse/GEOS-3996
String layer = getLayerId(TASMANIA_BM);
String request = "wms?version=1.3.0&service=wms&request=GetFeatureInfo" + "&layers="
+ layer + "&styles=&bbox=-44.5,146.5,-43,148&width=600&height=600"
+ "&info_format=" + GML3FeatureInfoOutputFormat.FORMAT + "&query_layers=" + layer
+ "&i=300&j=300&srs=EPSG:4326";
Document dom = getAsDOM(request);
print(dom);
XMLAssert.assertXpathEvaluatesTo("26.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:RED_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("70.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:GREEN_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("126.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:BLUE_BAND", dom);
}
/**
* Test that a GetFeatureInfo request shifted plus 360 degrees east has the same results.
*/
@Test
public void testCoverageGML31Plus360() throws Exception {
String layer = getLayerId(TASMANIA_BM);
String request = "wms?version=1.3.0&service=wms&request=GetFeatureInfo" + "&layers=" + layer
+ "&styles=&bbox=-44.5,506.5,-43,508&width=600&height=600" + "&info_format="
+ GML3FeatureInfoOutputFormat.FORMAT + "&query_layers=" + layer
+ "&i=300&j=300&srs=EPSG:4326";
Document dom = getAsDOM(request);
XMLAssert.assertXpathEvaluatesTo("26.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:RED_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("70.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:GREEN_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("126.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:BLUE_BAND", dom);
}
/**
* Test that a GetFeatureInfo request shifted minus 360 degrees east has the same results.
*/
@Test
public void testCoverageGML31Minus360() throws Exception {
String layer = getLayerId(TASMANIA_BM);
String request = "wms?version=1.3.0&service=wms&request=GetFeatureInfo" + "&layers=" + layer
+ "&styles=&bbox=-44.5,-213.5,-43,-212&width=600&height=600" + "&info_format="
+ GML3FeatureInfoOutputFormat.FORMAT + "&query_layers=" + layer
+ "&i=300&j=300&srs=EPSG:4326";
Document dom = getAsDOM(request);
XMLAssert.assertXpathEvaluatesTo("26.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:RED_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("70.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:GREEN_BAND", dom);
XMLAssert.assertXpathEvaluatesTo("126.0",
"//wfs:FeatureCollection/gml:featureMembers/wcs:BlueMarble/wcs:BLUE_BAND", dom);
}
@Test
public void testCoverageScales() throws Exception {
String layer = getLayerId(TASMANIA_BM);
String request = "wms?version=1.3.0&service=wms&request=GetFeatureInfo" + "&layers="
+ layer + "&styles=rasterScales&bbox=-44.5,146.5,-43,148"
+ "&info_format=text/html&query_layers=" + layer + "&i=300&j=300&srs=EPSG:4326";
// this one should be blank
Document dom = getAsDOM(request + "&width=300&height=300");
XMLAssert.assertXpathEvaluatesTo("0", "count(/html/body/table/tr/th)", dom);
// this one should draw the coverage
dom = getAsDOM(request + "&width=600&height=600");
// we also have the charset which may be platf. dep.
XMLAssert.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/th[. = 'RED_BAND'])", dom);
XMLAssert.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/th[. = 'GREEN_BAND'])",
dom);
XMLAssert
.assertXpathEvaluatesTo("1", "count(/html/body/table/tr/th[. = 'BLUE_BAND'])", dom);
}
@Test
public void testOutsideCoverage() throws Exception {
// a request which is way large on the west side, lots of blank space
String layer = getLayerId(TASMANIA_BM);
String request = "wms?version=1.3.0&service=wms&request=GetFeatureInfo" + "&layers="
+ layer + "&styles=raster&bbox=0,-90,148,-43"
+ "&info_format=text/html&query_layers=" + layer
+ "&width=300&height=300&i=10&j=150&srs=EPSG:4326";
// this one should be blank, but not be a service exception
Document dom = getAsDOM(request + "");
XMLAssert.assertXpathEvaluatesTo("1", "count(/html)", dom);
XMLAssert.assertXpathEvaluatesTo("0", "count(/html/body/table/tr/th)", dom);
}
/**
* Check we report back an exception when query_layer contains layers not part of LAYERS
*
*/
@Test
public void testUnknownQueryLayer() throws Exception {
String layers1 = getLayerId(MockData.FORESTS) + "," + getLayerId(MockData.LAKES);
String layers2 = getLayerId(MockData.FORESTS) + "," + getLayerId(MockData.BRIDGES);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&layers="
+ layers1 + "&query_layers=" + layers2 + "&width=20&height=20&i=10&j=10&info";
Document dom = getAsDOM(request + "");
XMLAssert.assertXpathEvaluatesTo("1", "count(/ogc:ServiceExceptionReport)", dom);
}
@Test
public void testDeriveLayersFromSLD() throws Exception {
String layers = getLayerId(MockData.FORESTS) + "," + getLayerId(MockData.LAKES);
String sld =
"<StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" " +
" xmlns:se=\"http://www.opengis.net/se\" version=\"1.1.0\"> "+
" <NamedLayer> "+
" <se:Name>"+getLayerId(MockData.FORESTS)+"</se:Name> "+
" </NamedLayer> "+
" <NamedLayer> "+
" <se:Name>"+getLayerId(MockData.LAKES)+"</se:Name> "+
" </NamedLayer> "+
"</StyledLayerDescriptor>";
// sld present & query_layers null/empty
String request1 = "wms?version=1.3&bbox=146.5,-44.5,148,-43&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&"
+ "sld_body=" + sld.replaceAll("=", "%3D") + "&width=20&height=20&x=10&y=10&info";
// sld present & query_layers equals layers derived by sld
String request2 = "wms?version=1.3&bbox=146.5,-44.5,148,-43&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&"
+ "sld_body=" + sld.replaceAll("=", "%3D") + "&query_layers=" + layers + "&width=20&height=20&x=10&y=10&info";
// normal request
String request3 = "wms?version=1.3&bbox=146.5,-44.5,148,-43&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&"
+ "layers=" + layers + "&query_layers=" + layers + "&width=20&height=20&x=10&y=10&info";
// sld not present & query_layers null
String invalidRequest1 = "wms?version=1.3&bbox=146.5,-44.5,148,-43&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&"
+ "layers=" + layers + "&width=20&height=20&x=10&y=10&info";
// sld present & query_layers contains unknown layer
String invalidRequest2 = "wms?version=1.3&bbox=146.5,-44.5,148,-43&styles=&format=jpeg&info_format=text/html&request=GetFeatureInfo&"
+ "sld_body=" + sld.replaceAll("=", "%3D") + "&query_layers=" + getLayerId(MockData.TASMANIA_BM) + "&width=20&height=20&x=10&y=10&info";
String result1 = getAsString(request1);
String result2 = getAsString(request2);
String result3 = getAsString(request3);
assertEquals(result1, result2);
assertEquals(result1, result3);
Document invalidResult1 = getAsDOM(invalidRequest1);
Document invalidResult2 = getAsDOM(invalidRequest2);
print(invalidResult1);
XMLAssert.assertXpathEvaluatesTo("1",
"count(//ogc:ServiceExceptionReport/ogc:ServiceException)", invalidResult1);
XMLAssert.assertXpathEvaluatesTo("1",
"count(//ogc:ServiceExceptionReport/ogc:ServiceException)", invalidResult2);
}
@Test
public void testLayerQualified() throws Exception {
String layer = "Forests";
String q = "?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
String request = "cite/Ponds/wms" + q;
Document dom = getAsDOM(request);
assertEquals("ServiceExceptionReport", dom.getDocumentElement().getNodeName());
request = "cite/Forests/wms" + q;
String result = getAsString(request);
// System.out.println(result);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
}
@Test
public void testXY() throws Exception {
String layer = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&x=10&y=10";
String result = getAsString(request);
// System.out.println(result);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
}
@Test
public void testXYGeo() throws Exception {
String layer = getLayerId(MockData.BASIC_POLYGONS);
String url = "wms?styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=292&height=512&x=147&y=360&srs=epsg:4326";
String request = url + "&VERSION=1.1.1&BBOX=-3.992187,-4.5,3.992188,9.5";
String result = getAsString(request);
assertTrue(result.indexOf("the_geom =") > 0);
request = url + "&VERSION=1.3.0&BBOX=-4.5,-3.992187,9.5,3.992188";
result = getAsString(request);
assertTrue(result.indexOf("the_geom =") > 0);
}
@Test
public void testXYProj() throws Exception {
String layer = getLayerId(MockData.POLYGONS);
String url = "wms?styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&WIDTH=512&HEIGHT=511&X=136&Y=380&srs=epsg:32615";
String request = url + "&VERSION=1.1.1&BBOX=499699.999705,499502.050472,501800.000326,501597.949528";
String result = getAsString(request);
System.out.println(result);
assertTrue(result.indexOf("polygonProperty =") > 0);
request = url + "&VERSION=1.3.0&BBOX=499699.999705,499502.050472,501800.000326,501597.949528";
result = getAsString(request);
assertTrue(result.indexOf("polygonProperty =") > 0);
}
@Test
public void testXYCoverage() throws Exception {
String layer = getLayerId(MockData.USA_WORLDIMG);
String url = "wms?styles=&format=jpeg&info_format=text/plain&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&WIDTH=512&HEIGHT=408&X=75&Y=132&srs=epsg:4326";
String request = url + "&VERSION=1.1.1&BBOX=-180,-143.4375,180,143.4375";
String result = getAsString(request);
Matcher m = Pattern.compile(
".*RED_BAND = (\\d+\\.\\d+).*GREEN_BAND = (\\d+\\.\\d+).*BLUE_BAND = (\\d+\\.\\d+).*",
Pattern.DOTALL).matcher(result);
assertTrue(m.matches());
double red = Double.parseDouble(m.group(1));
double green = Double.parseDouble(m.group(2));
double blue = Double.parseDouble(m.group(3));
request = url + "&VERSION=1.3.0&BBOX=-143.4375,-180,143.4375,180";
result = getAsString(request);
m = Pattern.compile(
".*RED_BAND = (\\d+\\.\\d+).*GREEN_BAND = (\\d+\\.\\d+).*BLUE_BAND = (\\d+\\.\\d+).*",
Pattern.DOTALL).matcher(result);
assertTrue(m.matches());
assertEquals(red, Double.parseDouble(m.group(1)),0.0000001);
assertEquals(green, Double.parseDouble(m.group(2)),0.0000001);
assertEquals(blue, Double.parseDouble(m.group(3)),0.0000001);
}
/**
* Test GetFeatureInfo for a coverage with longitudes greater than 300 degrees east.
*/
@Test
public void testSampleGrib() throws Exception {
String layer = getLayerId(SAMPLEGRIB);
String request = "wms?service=WMS&version=1.3.0&request=GetFeatureInfo&styles=&layers="
+ layer + "&query_layers=" + layer + "&info_format="
+ GML3FeatureInfoOutputFormat.FORMAT + "&width=300&height=400&i=150&j=100"
+ "&crs=EPSG:4326&bbox=2,302,10,308";
Document dom = getAsDOM(request);
print(dom);
XMLAssert.assertXpathEvaluatesTo("-0.095",
"substring(//wfs:FeatureCollection/gml:featureMembers/wcs:sampleGrib/wcs:GRAY_INDEX,1,6)",
dom);
}
/**
* Test GetFeatureInfo for a coverage with longitudes greater than 300 degrees east, with a request shifted 360 degrees west.
*/
@Test
public void testSampleGribWest() throws Exception {
String layer = getLayerId(SAMPLEGRIB);
String request = "wms?service=WMS&version=1.3.0&request=GetFeatureInfo&styles=&layers="
+ layer + "&query_layers=" + layer + "&info_format="
+ GML3FeatureInfoOutputFormat.FORMAT + "&width=300&height=400&i=150&j=100"
+ "&crs=EPSG:4326&bbox=2,-58,10,-52";
Document dom = getAsDOM(request);
XMLAssert.assertXpathEvaluatesTo("-0.095",
"substring(//wfs:FeatureCollection/gml:featureMembers/wcs:sampleGrib/wcs:GRAY_INDEX,1,6)",
dom);
}
/**
* Test GetFeatureInfo for a coverage with longitudes greater than 300 degrees east, with a request shifted 360 degrees west, using the Web
* Mercator projection.
*/
@Test
public void testSampleGribWebMercator() throws Exception {
String layer = getLayerId(SAMPLEGRIB);
String request = "wms?service=WMS&version=1.3.0&request=GetFeatureInfo&styles=&layers="
+ layer + "&query_layers=" + layer + "&info_format="
+ GML3FeatureInfoOutputFormat.FORMAT + "&width=300&height=400&i=150&j=100"
+ "&crs=EPSG:3857"
+ "&bbox=-6456530.466009867,222684.20850554455,-5788613.521250226,1118889.9748579597";
Document dom = getAsDOM(request);
XMLAssert.assertXpathEvaluatesTo("-0.095",
"substring(//wfs:FeatureCollection/gml:featureMembers/wcs:sampleGrib/wcs:GRAY_INDEX,1,6)",
dom);
}
/**
* Test GetFeatureInfo operation with lines styled with a line symbolizer. GenericLines layer
* geometry type is not defined so this use case will force the styles rendering machinery to
* deal with a generic geometry.
*/
@Test
public void testGetFeatureInfoOnLineStringsWithGenericGeometry() throws Exception {
// perform the get feature info request
String layer = getLayerId(GENERIC_LINES);
String request = "wms?" +
"SERVICE=WMS" +
"&VERSION=1.1.1" +
"&REQUEST=GetFeatureInfo" +
"&FORMAT=image/png" +
"&TRANSPARENT=true" +
"&STYLES=genericLinesStyle" +
"&WIDTH=101" +
"&HEIGHT=101" +
"&BBOX=0.72235107421875,-1.26617431640625,1.27716064453125,-0.71136474609375" +
"&SRS=EPSG:4326" +
"&FEATURE_COUNT=50" +
"&X=50" +
"&Y=50" +
"&QUERY_LAYERS=" + layer +
"&LAYERS=" + layer +
"&INFO_FORMAT=text/xml" +
"&PROPERTYNAME=name";
Document result = getAsDOM(request, true);
// xpath engine that will be used to check XML content
Map<String, String> namespaces = new HashMap<>();
namespaces.put("xlink", "http://www.w3.org/1999/xlink");
namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance");
namespaces.put("gml", "http://www.opengis.net/gml");
namespaces.put("wfs", "http://www.opengis.net/wfs");
namespaces.put("gs", "http://geoserver.org");
XpathEngine xpath = XMLUnit.newXpathEngine();
xpath.setNamespaceContext(new SimpleNamespaceContext(namespaces));
// let's check the XML response content
assertThat(xpath.evaluate("boolean(//wfs:FeatureCollection/gml:featureMember/gs:genericLines[@fid='line.2'][gs:name='line2'])", result), is("true"));
assertThat(xpath.evaluate("boolean(//wfs:FeatureCollection/gml:featureMember/gs:genericLines[@fid='line.3'][gs:name='line3'])", result), is("true"));
}
@Test
public void testSchemaLeak() throws Exception {
String layer = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&styles=&format=jpeg&info_format=" + GML3FeatureInfoOutputFormat.FORMAT + "&request=GetFeatureInfo&layers="
+ layer + "&query_layers=" + layer + "&width=20&height=20&i=10&j=10";
// prime system, make sure everything is wired
getAsDOM(request);
// count how many imports in the OGC filter schema
XSDSchema schema = OGC.getInstance().getSchema();
int expectedImportCounts = schema.getReferencingDirectives().size();
// now check how many there are after anothe request, should not go up
getAsDOM(request);
int actualImportCounts = schema.getReferencingDirectives().size();
assertEquals(expectedImportCounts, actualImportCounts);
}
@Test
public void testQueryableAndNonQueryableLayersWithStyles() throws Exception {
String states = getLayerId(STATES);
String forests = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&format=jpeg" +
"&info_format=text/plain&request=GetFeatureInfo&width=20&height=20&i=10&j=10" +
"&layers=" + states + "," + forests + "&query_layers=" + states + "," + forests +
"&styles=Population,Forests";
String result = getAsString(request);
// System.out.println(result);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
}
@Test
public void testQueryableAndNonQueryableLayersWithCqlFilter() throws Exception {
String states = getLayerId(STATES);
String forests = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&format=jpeg" +
"&info_format=text/plain&request=GetFeatureInfo&width=20&height=20&i=10&j=10" +
"&layers=" + states + "," + forests + "&query_layers=" + states + "," + forests +
"&styles=&cql_filter=PERSONS>25000000;NAME='Green Forest'";
String result = getAsString(request);
// System.out.println(result);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
}
@Test
public void testQueryableAndNonQueryableLayersWithFilter() throws Exception {
String states = getLayerId(STATES);
String forests = getLayerId(MockData.FORESTS);
String request = "wms?version=1.3.0&bbox=-0.002,-0.002,0.002,0.002&format=jpeg" +
"&info_format=text/plain&request=GetFeatureInfo&width=20&height=20&i=10&j=10" +
"&layers=" + states + "," + forests + "&query_layers=" + states + "," + forests +
"&styles=&filter=" +
"(%3CFilter%3E%3CPropertyIsGreaterThan%3E%3CPropertyName%3EPERSONS%3C/PropertyName%3E%3CLiteral%3E25000000%3C/Literal%3E%3C/PropertyIsGreaterThan%3E%3C/Filter%3E)" +
"(%3CFilter%3E%3CPropertyIsEqualTo%3E%3CPropertyName%3ENAME%3C/PropertyName%3E%3CLiteral%3EGreen%20Forest%3C/Literal%3E%3C/PropertyIsEqualTo%3E%3C/Filter%3E)";
String result = getAsString(request);
// System.out.println(result);
assertNotNull(result);
assertTrue(result.indexOf("Green Forest") > 0);
}
}