/* (c) 2014 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.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathNotExists;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.config.CapabilitiesCacheHeadersCallback;
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerInfo;
import org.geoserver.config.ResourceErrorHandling;
import org.geoserver.data.test.CiteTestData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.platform.GeoServerExtensions;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class GetCapabilitiesTest extends WFSTestSupport {
@Before
public void revert() throws Exception {
revertLayer(CiteTestData.UPDATES);
}
@Override
protected void setUpInternal(SystemTestData dataDirectory) throws Exception {
DataStoreInfo di = getCatalog().getDataStoreByName(CiteTestData.CITE_PREFIX);
di.setEnabled(false);
getCatalog().save(di);
}
@Test
public void testGet() throws Exception {
Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=getCapabilities");
assertEquals("WFS_Capabilities", doc.getDocumentElement()
.getNodeName());
XpathEngine xpath = XMLUnit.newXpathEngine();
assertTrue(xpath.getMatchingNodes("//wfs:FeatureType", doc).getLength() > 0);
}
@Test
public void testSkipMisconfiguredLayers() throws Exception {
// configure geoserver to skip misconfigured layers
GeoServerInfo global = getGeoServer().getGlobal();
global.setResourceErrorHandling(ResourceErrorHandling.SKIP_MISCONFIGURED_LAYERS);
getGeoServer().save(global);
// introduce misconfiguration
FeatureTypeInfo ftype = getCatalog().getFeatureTypeByName(CiteTestData.UPDATES.getLocalPart());
ftype.setLatLonBoundingBox(null);
getCatalog().save(ftype);
// fetch capabilities document
Document doc = getAsDOM("wfs?version=1.0.0&service=WFS&request=getCapabilities");
// print(doc);
int count = 0;
for (FeatureTypeInfo ft : getCatalog().getFeatureTypes()) {
if (ft.enabled()) count++;
}
// print(doc);
assertXpathEvaluatesTo(String.valueOf(count - 1), "count(//wfs:FeatureType)", doc);
}
@Test
public void testNamespaceFilter() throws Exception {
// filter on an existing namespace
Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=getCapabilities&namespace=sf");
Element e = doc.getDocumentElement();
assertEquals("WFS_Capabilities", e.getLocalName());
XpathEngine xpath = XMLUnit.newXpathEngine();
assertTrue(xpath.getMatchingNodes("//wfs:FeatureType/wfs:Name[starts-with(., sf)]", doc).getLength() > 0);
assertEquals(0, xpath.getMatchingNodes("//wfs:FeatureType/wfs:Name[not(starts-with(., sf))]", doc).getLength());
// try again with a missing one
doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=getCapabilities&namespace=NotThere");
e = doc.getDocumentElement();
assertEquals("WFS_Capabilities", e.getLocalName());
assertEquals(0, xpath.getMatchingNodes("//wfs:FeatureType", doc).getLength());
}
@Test
public void testPost() throws Exception {
String xml = "<GetCapabilities service=\"WFS\" version=\"1.0.0\""
+ " xmlns=\"http://www.opengis.net/wfs\" "
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
+ " xsi:schemaLocation=\"http://www.opengis.net/wfs "
+ " http://schemas.opengis.net/wfs/1.0.0/WFS-basic.xsd\"/>";
Document doc = postAsDOM("wfs", xml);
assertEquals("WFS_Capabilities", doc.getDocumentElement().getNodeName());
}
@Test
public void testOutputFormats() throws Exception {
Document doc = getAsDOM("wfs?service=WFS&request=getCapabilities&version=1.0.0");
Element outputFormats = getFirstElementByTagName(doc, "ResultFormat");
NodeList formats = outputFormats.getChildNodes();
TreeSet s1 = new TreeSet();
for ( int i = 0; i < formats.getLength(); i++ ) {
String format = formats.item(i).getNodeName();
s1.add( format );
}
List extensions = GeoServerExtensions.extensions( WFSGetFeatureOutputFormat.class );
TreeSet s2 = new TreeSet();
for ( Iterator e = extensions.iterator(); e.hasNext(); ) {
WFSGetFeatureOutputFormat extension = (WFSGetFeatureOutputFormat) e.next();
s2.add( extension.getCapabilitiesElementName() );
}
assertEquals( s1, s2 );
}
@Test
public void testSupportedSpatialOperators() throws Exception {
Document doc = getAsDOM("wfs?service=WFS&request=getCapabilities&version=1.0.0");
Element spatialOperators = getFirstElementByTagName(doc,
"ogc:Spatial_Operators");
NodeList ops = spatialOperators.getChildNodes();
TreeSet<String> o = new TreeSet<String>();
for (int i = 0; i < ops.getLength(); i++) {
String operator = ops.item(i).getLocalName();
o.add(operator);
}
List<String> expectedSpatialOperators = getSupportedSpatialOperatorsList(true);
assertEquals(expectedSpatialOperators.size(), o.size());
assertTrue(o.containsAll(expectedSpatialOperators));
}
@Test
public void testTypeNameCount() throws Exception {
// filter on an existing namespace
Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=getCapabilities");
Element e = doc.getDocumentElement();
assertEquals("WFS_Capabilities", e.getLocalName());
XpathEngine xpath = XMLUnit.newXpathEngine();
final List<FeatureTypeInfo> enabledTypes = getCatalog().getFeatureTypes();
for (Iterator<FeatureTypeInfo> it = enabledTypes.iterator(); it.hasNext();) {
FeatureTypeInfo ft = it.next();
if (!ft.enabled()) {
it.remove();
}
}
final int enabledCount = enabledTypes.size();
assertEquals(enabledCount, xpath.getMatchingNodes(
"/wfs:WFS_Capabilities/wfs:FeatureTypeList/wfs:FeatureType", doc).getLength());
}
@Test
public void testTypeNames() throws Exception {
// filter on an existing namespace
Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=getCapabilities");
print (doc);
Element e = doc.getDocumentElement();
assertEquals("WFS_Capabilities", e.getLocalName());
final List<FeatureTypeInfo> enabledTypes = getCatalog().getFeatureTypes();
for (Iterator<FeatureTypeInfo> it = enabledTypes.iterator(); it.hasNext();) {
FeatureTypeInfo ft = it.next();
if (ft.enabled()) {
String prefixedName = ft.getPrefixedName();
String xpathExpr = "/wfs:WFS_Capabilities/wfs:FeatureTypeList/"
+ "wfs:FeatureType/wfs:Name[text()=\"" + prefixedName + "\"]";
XMLAssert.assertXpathExists(xpathExpr, doc);
}
}
}
@Test
public void testWorkspaceQualified() throws Exception {
// filter on an existing namespace
Document doc = getAsDOM("sf/wfs?service=WFS&version=1.0.0&request=getCapabilities");
Element e = doc.getDocumentElement();
assertEquals("WFS_Capabilities", e.getLocalName());
XpathEngine xpath = XMLUnit.newXpathEngine();
assertTrue(xpath.getMatchingNodes("//wfs:FeatureType/wfs:Name[starts-with(., sf)]", doc).getLength() > 0);
assertEquals(0, xpath.getMatchingNodes("//wfs:FeatureType/wfs:Name[not(starts-with(., sf))]", doc).getLength());
assertEquals(6, xpath.getMatchingNodes("//wfs:Get[contains(@onlineResource,'sf/wfs')]", doc).getLength());
assertEquals(6, xpath.getMatchingNodes("//wfs:Post[contains(@onlineResource,'sf/wfs')]", doc).getLength());
//TODO: test with a non existing workspace
}
@Test
public void testLayerQualified() throws Exception {
// filter on an existing namespace
Document doc = getAsDOM("sf/PrimitiveGeoFeature/wfs?service=WFS&version=1.0.0&request=getCapabilities");
Element e = doc.getDocumentElement();
assertEquals("WFS_Capabilities", e.getLocalName());
XpathEngine xpath = XMLUnit.newXpathEngine();
assertEquals(1, xpath.getMatchingNodes("//wfs:FeatureType/wfs:Name[starts-with(., sf)]", doc).getLength());
assertEquals(0, xpath.getMatchingNodes("//wfs:FeatureType/wfs:Name[not(starts-with(., sf))]", doc).getLength());
assertEquals(6, xpath.getMatchingNodes("//wfs:Get[contains(@onlineResource,'sf/PrimitiveGeoFeature/wfs')]", doc).getLength());
assertEquals(6, xpath.getMatchingNodes("//wfs:Post[contains(@onlineResource,'sf/PrimitiveGeoFeature/wfs')]", doc).getLength());
//TODO: test with a non existing workspace
}
@Test
public void testNonAdvertisedLayer() throws Exception {
String layerId = getLayerId(CiteTestData.MLINES);
LayerInfo layer = getCatalog().getLayerByName(layerId);
try {
// now you see me
Document dom = getAsDOM("wfs?request=getCapabilities&version=1.0.0");
assertXpathExists("//wfs:FeatureType[wfs:Name='" + layerId + "']", dom);
// now you don't!
layer.setAdvertised(false);
getCatalog().save(layer);
dom = getAsDOM("wfs?request=getCapabilities&version=1.0.0");
assertXpathNotExists("//wfs:FeatureType[wfs:Name = '" + layerId + "']", dom);
} finally {
layer.setAdvertised(true);
getCatalog().save(layer);
}
}
@Test
public void testCachingHeaders() throws Exception {
// Check the cache control headers are set
MockHttpServletRequest request = createGetRequestWithHeaders("wfs?service=WFS&version=1.0.0&request=getCapabilities");
MockHttpServletResponse response = dispatch(request);
assertEquals(HttpStatus.OK.value(), response.getStatus());
// check caching headers
assertEquals("max-age=0, must-revalidate", response.getHeader(HttpHeaders.CACHE_CONTROL));
}
@Test
public void testCachingHeadersDisabled() throws Exception {
CapabilitiesCacheHeadersCallback callback = GeoServerExtensions.bean(CapabilitiesCacheHeadersCallback.class);
boolean backup = callback.isCapabilitiesCacheHeadersEnabled();
try {
callback.setCapabilitiesCacheHeadersEnabled(false);
// first request, get the etag
MockHttpServletRequest request = createGetRequestWithHeaders("wfs?service=WFS&version=1.0.0&request=getCapabilities");
MockHttpServletResponse response = dispatch(request);
assertEquals(HttpStatus.OK.value(), response.getStatus());
// check caching headers are not there
assertNull(response.getHeader(HttpHeaders.ETAG));
assertNull(response.getHeader(HttpHeaders.CACHE_CONTROL));
} finally {
callback.setCapabilitiesCacheHeadersEnabled(backup);
}
}
MockHttpServletRequest createGetRequestWithHeaders(String path, String... headers) {
MockHttpServletRequest request = createRequest( path );
request.setMethod( "GET" );
request.setContent(new byte[]{});
for(int i = 0; i < headers.length - 1; i+=2) {
request.addHeader(headers[i], headers[i+1]);
}
return request;
}
}