/* (c) 2014 - 2017 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.wfs;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Collections;
import javax.xml.namespace.QName;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.catalog.StoreInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
public class GetFeatureTest extends WFSTestSupport {
public static QName NULL_GEOMETRIES = new QName(SystemTestData.CITE_URI, "NullGeometries", SystemTestData.CITE_PREFIX);
public static QName FIFTEEN_DUPLICATE = new QName(SystemTestData.CITE_URI, "Fifteen", SystemTestData.CITE_PREFIX);
@Override
protected void setUpInternal(SystemTestData data) throws Exception {
WFSInfo wfs = getWFS();
wfs.setFeatureBounding(true);
getGeoServer().save(wfs);
data.addVectorLayer (NULL_GEOMETRIES, Collections.EMPTY_MAP, getClass(), getCatalog());
data.addVectorLayer (FIFTEEN_DUPLICATE, Collections.EMPTY_MAP, getClass(), getCatalog());
}
@Before
public void resetFifteen() throws IOException {
revertLayer(MockData.FIFTEEN);
}
@Test
public void testGet() throws Exception {
testGetFifteenAll("wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs");
}
@Test
public void testPostForm() throws Exception {
String contentType = "application/x-www-form-urlencoded; charset=UTF-8";
String body = "request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs";
MockHttpServletRequest request = createRequest("wfs");
request.setMethod("POST");
request.setContent(body.getBytes("UTF-8"));
// this is normally done by the servlet container, but the mock system won't do it
request.addParameter("request", "GetFeature");
request.addParameter("typename", "cdf:Fifteen");
request.addParameter("version", "1.0.0");
request.addParameter("service", "wfs");
request.setContentType(contentType);
MockHttpServletResponse response = dispatch(request);
try (ByteArrayInputStream bis = new ByteArrayInputStream(
response.getContentAsByteArray())) {
Document doc = dom(bis);
assertEquals("wfs:FeatureCollection", doc.getDocumentElement().getNodeName());
NodeList featureMembers = doc.getElementsByTagName("gml:featureMember");
assertEquals(15, featureMembers.getLength());
}
}
@Test
public void testGetPropertyNameEmpty() throws Exception {
testGetFifteenAll("wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs&propertyname=");
}
@Test
public void testGetFilterEmpty() throws Exception {
testGetFifteenAll("wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs&filter=");
}
@Test
public void testGetPropertyNameStar() throws Exception {
testGetFifteenAll("wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs&propertyname=*");
}
private void testGetFifteenAll(String request) throws Exception {
Document doc = getAsDOM(request);
assertEquals("wfs:FeatureCollection", doc.getDocumentElement()
.getNodeName());
NodeList featureMembers = doc.getElementsByTagName("gml:featureMember");
assertEquals(15, featureMembers.getLength());
}
// see GEOS-1893
@Test
public void testGetMissingParams() throws Exception {
Document doc = getAsDOM("wfs?request=GetFeature&typeNameWrongParam=cdf:Fifteen&version=1.0.0&service=wfs");
// trick: the document specifies a namespace with schema reference, as a result xpath expressions
// do work only if fully qualified
XMLAssert.assertXpathEvaluatesTo("1", "count(//ogc:ServiceException)", doc);
XMLAssert.assertXpathEvaluatesTo("MissingParameterValue", "//ogc:ServiceException/@code", doc);
}
@Test
public void testAlienNamespace() throws Exception {
// if the namespace is not known, complain with a service exception
Document doc = getAsDOM("wfs?request=GetFeature&typename=youdontknowme:Fifteen&version=1.0.0&service=wfs");
assertEquals("ServiceExceptionReport", doc.getDocumentElement()
.getNodeName());
}
@Test
public void testGetNullGeometies() throws Exception {
Document doc;
doc = getAsDOM("wfs?request=GetFeature&typeName=" + getLayerId(NULL_GEOMETRIES) + "&version=1.0.0&service=wfs");
// print(doc);
XMLAssert.assertXpathEvaluatesTo("1", "count(//cite:NullGeometries[@fid=\"NullGeometries.1107531701010\"]/gml:boundedBy)", doc);
XMLAssert.assertXpathEvaluatesTo("0", "count(//cite:NullGeometries[@fid=\"NullGeometries.1107531701011\"]/boundedBy)", doc);
}
// see GEOS-1287
@Test
public void testGetWithFeatureId() throws Exception {
Document doc;
doc = getAsDOM("wfs?request=GetFeature&typeName=cdf:Fifteen&version=1.0.0&service=wfs&featureid=Fifteen.2");
// super.print(doc);
assertEquals("wfs:FeatureCollection", doc.getDocumentElement().getNodeName());
XMLAssert.assertXpathEvaluatesTo("1", "count(//wfs:FeatureCollection/gml:featureMember)",
doc);
XMLAssert.assertXpathEvaluatesTo("Fifteen.2",
"//wfs:FeatureCollection/gml:featureMember/cdf:Fifteen/@fid", doc);
doc = getAsDOM("wfs?request=GetFeature&typeName=cite:NamedPlaces&version=1.0.0&service=wfs&featureId=NamedPlaces.1107531895891");
//super.print(doc);
assertEquals("wfs:FeatureCollection", doc.getDocumentElement().getNodeName());
XMLAssert.assertXpathEvaluatesTo("1", "count(//wfs:FeatureCollection/gml:featureMember)",
doc);
XMLAssert.assertXpathEvaluatesTo("NamedPlaces.1107531895891",
"//wfs:FeatureCollection/gml:featureMember/cite:NamedPlaces/@fid", doc);
}
@Test
public void testPost() throws Exception {
String xml = "<wfs:GetFeature " + "service=\"WFS\" "
+ "version=\"1.0.0\" "
+ "xmlns:cdf=\"http://www.opengis.net/cite/data\" "
+ "xmlns:ogc=\"http://www.opengis.net/ogc\" "
+ "xmlns:wfs=\"http://www.opengis.net/wfs\" " + "> "
+ "<wfs:Query typeName=\"cdf:Other\"> "
+ "<ogc:PropertyName>cdf:string2</ogc:PropertyName> "
+ "</wfs:Query> " + "</wfs:GetFeature>";
Document doc = postAsDOM("wfs", xml);
assertEquals("wfs:FeatureCollection", doc.getDocumentElement()
.getNodeName());
NodeList featureMembers = doc.getElementsByTagName("gml:featureMember");
assertFalse(featureMembers.getLength() == 0);
}
@Test
public void testPostWithFilter() throws Exception {
String xml = "<wfs:GetFeature " + "service=\"WFS\" "
+ "version=\"1.0.0\" " + "outputFormat=\"GML2\" "
+ "xmlns:cdf=\"http://www.opengis.net/cite/data\" "
+ "xmlns:wfs=\"http://www.opengis.net/wfs\" "
+ "xmlns:ogc=\"http://www.opengis.net/ogc\" > "
+ "<wfs:Query typeName=\"cdf:Other\"> "
+ "<ogc:PropertyName>cdf:string2</ogc:PropertyName> "
+ "<ogc:Filter> " + "<ogc:PropertyIsEqualTo> "
+ "<ogc:PropertyName>cdf:integers</ogc:PropertyName> "
+ "<ogc:Add> " + "<ogc:Literal>4</ogc:Literal> "
+ "<ogc:Literal>3</ogc:Literal> " + "</ogc:Add> "
+ "</ogc:PropertyIsEqualTo> " + "</ogc:Filter> "
+ "</wfs:Query> " + "</wfs:GetFeature>";
Document doc = postAsDOM("wfs", xml);
assertEquals("wfs:FeatureCollection", doc.getDocumentElement()
.getNodeName());
NodeList featureMembers = doc.getElementsByTagName("gml:featureMember");
assertFalse(featureMembers.getLength() == 0);
}
@Test
public void testLax() throws Exception {
String xml =
"<GetFeature version='1.1.0' xmlns:gml=\"http://www.opengis.net/gml\">" +
" <Query typeName=\"" + SystemTestData.BUILDINGS.getLocalPart() + "\">" +
" <PropertyName>ADDRESS</PropertyName>" +
" <Filter>" +
" <PropertyIsEqualTo>" +
" <PropertyName>ADDRESS</PropertyName>" +
" <Literal>123 Main Street</Literal>" +
" </PropertyIsEqualTo>" +
" </Filter>" +
" </Query>" +
"</GetFeature>";
Document doc = postAsDOM( "wfs", xml );
//print( doc );
assertEquals("wfs:FeatureCollection", doc.getDocumentElement()
.getNodeName());
NodeList featureMembers = doc.getElementsByTagName("cite:Buildings");
assertEquals(1,featureMembers.getLength());
}
@Test
public void testMixed() throws Exception {
String xml = "<wfs:GetFeature " + "service=\"WFS\" "
+ "version=\"1.0.0\" "
+ "xmlns:cdf=\"http://www.opengis.net/cite/data\" "
+ "xmlns:ogc=\"http://www.opengis.net/ogc\" "
+ "xmlns:wfs=\"http://www.opengis.net/wfs\" " + "> "
+ "<wfs:Query typeName=\"cdf:Other\"> "
+ "<ogc:PropertyName>cdf:string2</ogc:PropertyName> "
+ "</wfs:Query> " + "</wfs:GetFeature>";
Document doc = postAsDOM("wfs?request=GetFeature", xml);
assertEquals("wfs:FeatureCollection", doc.getDocumentElement()
.getNodeName());
NodeList featureMembers = doc.getElementsByTagName("gml:featureMember");
assertFalse(featureMembers.getLength() == 0);
}
@Test
public void testLikeMatchCase() throws Exception {
// first run, without matching case, should match both buildings
String xml =
"<GetFeature version='1.1.0' xmlns:gml=\"http://www.opengis.net/gml\">" +
" <Query typeName=\"" + SystemTestData.BUILDINGS.getLocalPart() + "\">" +
" <PropertyName>ADDRESS</PropertyName>" +
" <Filter>" +
" <PropertyIsLike wildCard=\"*\" singleChar=\".\" escapeChar=\"\\\" matchCase=\"false\">" +
" <PropertyName>ADDRESS</PropertyName>" +
" <Literal>* MAIN STREET</Literal>" +
" </PropertyIsLike>" +
" </Filter>" +
" </Query>" +
"</GetFeature>";
Document doc = postAsDOM( "wfs", xml );
assertEquals("wfs:FeatureCollection", doc.getDocumentElement()
.getNodeName());
NodeList featureMembers = doc.getElementsByTagName("cite:Buildings");
assertEquals(2,featureMembers.getLength());
// second run, with match case, should match none
xml =
"<GetFeature version='1.1.0' xmlns:gml=\"http://www.opengis.net/gml\">" +
" <Query typeName=\"" + SystemTestData.BUILDINGS.getLocalPart() + "\">" +
" <PropertyName>ADDRESS</PropertyName>" +
" <Filter>" +
" <PropertyIsLike wildCard=\"*\" singleChar=\".\" escapeChar=\"\\\" matchCase=\"true\">" +
" <PropertyName>ADDRESS</PropertyName>" +
" <Literal>* MAIN STREET</Literal>" +
" </PropertyIsLike>" +
" </Filter>" +
" </Query>" +
"</GetFeature>";
doc = postAsDOM( "wfs", xml );
assertEquals("wfs:FeatureCollection", doc.getDocumentElement()
.getNodeName());
featureMembers = doc.getElementsByTagName("cite:Buildings");
assertEquals(0,featureMembers.getLength());
}
@Test
public void testWorkspaceQualified() throws Exception {
testGetFifteenAll("cdf/wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs");
testGetFifteenAll("cdf/wfs?request=GetFeature&typename=Fifteen&version=1.0.0&service=wfs");
Document doc = getAsDOM("sf/wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs");
XMLAssert.assertXpathEvaluatesTo("1", "count(//ogc:ServiceException)", doc);
}
@Test
public void testLayerQualified() throws Exception {
testGetFifteenAll("cdf/Fifteen/wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs");
testGetFifteenAll("cdf/Fifteen/wfs?request=GetFeature&typename=Fifteen&version=1.0.0&service=wfs");
Document doc = getAsDOM("cdf/Fifteen/wfs?request=GetFeature&typename=cdf:Seven&version=1.0.0&service=wfs");
XMLAssert.assertXpathEvaluatesTo("1", "count(//ogc:ServiceException)", doc);
}
@Test
public void testMultiLayer() throws Exception {
Document doc = getAsDOM("/wfs?request=GetFeature&typename=" + getLayerId(SystemTestData.BASIC_POLYGONS)
+ "," + getLayerId(SystemTestData.BRIDGES) + "&version=1.0.0&service=wfs");
// print(doc);
XpathEngine engine = XMLUnit.newXpathEngine();
String schemaLocation = engine.evaluate("wfs:FeatureCollection/@xsi:schemaLocation", doc);
assertNotNull(schemaLocation);
String[] parsedLocations = schemaLocation.split("\\s+");
// System.out.println(Arrays.toString(parsedLocations));
int i = 0;
for (; i < parsedLocations.length; i+=2) {
if(parsedLocations[i].equals("http://www.opengis.net/cite")) {
assertEquals("http://localhost:8080/geoserver/wfs?service=WFS&version=1.0.0&request=DescribeFeatureType&typeName=cite%3ABasicPolygons,cite%3ABridges", parsedLocations[i+1]);
break;
}
}
if(i >= parsedLocations.length) {
fail("Could not find the http://www.opengis.net/cite schema location!");
}
}
@Test
public void testStrictComplianceBBoxValidator() throws Exception {
GeoServer geoServer = getGeoServer();
WFSInfo service = geoServer.getService(WFSInfo.class);
try {
service.setCiteCompliant(true);
geoServer.save(service);
final QName typeName = MockData.FORESTS;
// used to throw an error since it was not accounting for the bbox epsg code
String path = "ows?service=WFS&version=1.1.0&request=GetFeature&typeName="
+ getLayerId(typeName) + "&bbox=1818131,6142575,1818198,6142642,EPSG:3857&srsName=EPSG:4326";
Document doc = getAsDOM(path);
print(doc);
XMLAssert.assertXpathEvaluatesTo("1", "count(//wfs:FeatureCollection)", doc);
} finally {
service.setCiteCompliant(false);
geoServer.save(service);
}
}
@Test
public void testRequestDisabledResource() throws Exception {
Catalog catalog = getCatalog();
ResourceInfo fifteen = catalog.getResourceByName(getLayerId(MockData.FIFTEEN),
ResourceInfo.class);
fifteen.setEnabled(false);
catalog.save(fifteen);
Document doc = getAsDOM("wfs?request=GetFeature&typename=cdf:Fifteen&version=1.0.0&service=wfs");
// print(doc);
XMLAssert.assertXpathEvaluatesTo("1", "count(//ogc:ServiceException)", doc);
XMLAssert.assertXpathEvaluatesTo("InvalidParameterValue", "//ogc:ServiceException/@code",
doc);
XMLAssert.assertXpathEvaluatesTo("typeName", "//ogc:ServiceException/@locator", doc);
}
/**
* Test that a request for a resource from a disabled store fails.
*/
@Test
public void testRequestDisabledStore() throws Exception {
Catalog catalog = getCatalog();
StoreInfo store = catalog.getStoreByName("cdf", DataStoreInfo.class);
try {
store.setEnabled(false);
catalog.save(store);
Document doc = getAsDOM(
"wfs?service=WFS&version=1.0.0&request=GetFeature&typename=cdf:Fifteen");
// print(doc);
XMLAssert.assertXpathEvaluatesTo("1", "count(//ogc:ServiceException)", doc);
XMLAssert.assertXpathEvaluatesTo("InvalidParameterValue",
"//ogc:ServiceException/@code", doc);
XMLAssert.assertXpathEvaluatesTo("typeName", "//ogc:ServiceException/@locator", doc);
} finally {
store.setEnabled(true);
catalog.save(store);
}
}
/**
* Tests CQL filter
*
*/
@Test
public void testCQLFilter() throws Exception {
String layer = getLayerId(MockData.FORESTS);
String request = "wfs?request=GetFeature&typename=" + layer + "&version=1.0.0&service=wfs";
Document doc = getAsDOM(request);
NodeList featureMembers = doc.getElementsByTagName("gml:featureMember");
assertTrue(featureMembers.getLength() > 0);
// Add CQL filter
FeatureTypeInfo info = getCatalog().getFeatureTypeByName(layer);
info.setCqlFilter("NAME LIKE 'Red%'");
getCatalog().save(info);
doc = getAsDOM(request);
featureMembers = doc.getElementsByTagName("gml:featureMember");
assertTrue(featureMembers.getLength() == 0);
}
}