/* (c) 2014 - 2015 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.v1_1; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.List; import java.util.Set; 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.MetadataLinkInfo; import org.geoserver.config.GeoServerInfo; import org.geoserver.data.test.CiteTestData; import org.geoserver.data.test.MockData; import org.geoserver.data.test.MockTestData; import org.geoserver.data.test.SystemTestData; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.wfs.WFSGetFeatureOutputFormat; import org.geoserver.wfs.WFSInfo; import org.geoserver.wfs.WFSTestSupport; import org.junit.Before; import org.junit.Test; 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); revertLayer(CiteTestData.BUILDINGS); revertLayer(MockData.MPOLYGONS); } @Override protected void setUpInternal(SystemTestData dataDirectory) throws Exception { DataStoreInfo di = getCatalog().getDataStoreByName(CiteTestData.CITE_PREFIX); di.setEnabled(false); getCatalog().save(di); GeoServerInfo global = getGeoServer().getGlobal(); global.getSettings().setProxyBaseUrl("src/test/resources/geoserver"); getGeoServer().save(global); } @Test public void testGet() throws Exception { Document doc = getAsDOM("wfs?service=WFS&request=getCapabilities&version=1.1.0"); String docText = getAsString("wfs?service=WFS&request=GetCapabilities&version=1.1.0"); assertEquals("wfs:WFS_Capabilities", doc.getDocumentElement() .getNodeName()); assertEquals("1.1.0", doc.getDocumentElement().getAttribute("version")); XpathEngine xpath = XMLUnit.newXpathEngine(); assertTrue(xpath.getMatchingNodes("//wfs:FeatureType", doc).getLength() > 0); assertFalse(docText, docText.contains("xmlns:xml=")); } @Test public void testNamespaceFilter() throws Exception { // filter on an existing namespace Document doc = getAsDOM("wfs?service=WFS&version=1.1.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.1.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.1.0'" + " xmlns=\"http://www.opengis.net/wfs\" " + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + " xmlns:ows=\"http://www.opengis.net/ows\" " + " xsi:schemaLocation=\"http://www.opengis.net/wfs " + " http://schemas.opengis.net/wfs/1.1.0/wfs.xsd\">" + "<ows:AcceptVersions><ows:Version>1.1.0</ows:Version></ows:AcceptVersions>" + "</GetCapabilities>"; Document doc = postAsDOM("wfs", xml); assertEquals("wfs:WFS_Capabilities", doc.getDocumentElement() .getNodeName()); assertEquals("1.1.0", doc.getDocumentElement().getAttribute("version")); } @Test public void testPostNoSchemaLocation() throws Exception { String xml = "<GetCapabilities service=\"WFS\" version='1.1.0'" + " xmlns=\"http://www.opengis.net/wfs\" " + " xmlns:ows=\"http://www.opengis.net/ows\" " + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" >" + "<ows:AcceptVersions><ows:Version>1.1.0</ows:Version></ows:AcceptVersions>" + "</GetCapabilities>"; Document doc = postAsDOM("wfs", xml); assertEquals("wfs:WFS_Capabilities", doc.getDocumentElement() .getNodeName()); assertEquals("1.1.0", doc.getDocumentElement().getAttribute("version")); } @Test public void testOutputFormats() throws Exception { Document doc = getAsDOM("wfs?service=WFS&request=getCapabilities&version=1.1.0"); // print(doc); // let's look for the outputFormat parameter values inside of the GetFeature operation metadata XpathEngine engine = XMLUnit.newXpathEngine(); NodeList formats = engine.getMatchingNodes( "//ows:Operation[@name=\"GetFeature\"]/ows:Parameter[@name=\"outputFormat\"]/ows:Value", doc); Set<String> s1 = new TreeSet<String>(); for ( int i = 0; i < formats.getLength(); i++ ) { String format = formats.item(i).getFirstChild().getNodeValue(); s1.add( format ); } List<WFSGetFeatureOutputFormat> extensions = GeoServerExtensions.extensions( WFSGetFeatureOutputFormat.class ); Set<String> s2 = new TreeSet<String>(); for ( Iterator e = extensions.iterator(); e.hasNext(); ) { WFSGetFeatureOutputFormat extension = (WFSGetFeatureOutputFormat) e.next(); s2.addAll( extension.getOutputFormats() ); } assertEquals( s1, s2 ); } @Test public void testSupportedSpatialOperators() throws Exception { Document doc = getAsDOM("wfs?service=WFS&request=getCapabilities&version=1.1.0"); // let's look for the spatial capabilities, extract all the spatial operators XpathEngine engine = XMLUnit.newXpathEngine(); NodeList spatialOperators = engine .getMatchingNodes( "//ogc:Spatial_Capabilities/ogc:SpatialOperators/ogc:SpatialOperator/@name", doc); Set<String> ops = new TreeSet<String>(); for (int i = 0; i < spatialOperators.getLength(); i++) { String format = spatialOperators.item(i).getFirstChild() .getNodeValue(); ops.add(format); } List<String> expectedSpatialOperators = getSupportedSpatialOperatorsList(false); assertEquals(expectedSpatialOperators.size(), ops.size()); assertTrue(ops.containsAll(expectedSpatialOperators)); } @Test public void testFunctionArgCount() throws Exception { Document doc = getAsDOM("wfs?service=WFS&request=getCapabilities&version=1.1.0"); // print(doc); // let's check the argument count of "abs" function XMLAssert.assertXpathEvaluatesTo("1", "//ogc:FunctionName[text()=\"abs\"]/@nArgs", doc); } @Test public void testTypeNameCount() throws Exception { // filter on an existing namespace Document doc = getAsDOM("wfs?service=WFS&version=1.1.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.1.0&request=getCapabilities"); 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.prefixedName(); String xpathExpr = "/wfs:WFS_Capabilities/wfs:FeatureTypeList/" + "wfs:FeatureType/wfs:Name[text()=\"" + prefixedName + "\"]"; XMLAssert.assertXpathExists(xpathExpr, doc); } } } @Test public void testLayerQualified() throws Exception { // filter on an existing namespace Document doc = getAsDOM("sf/PrimitiveGeoFeature/wfs?service=WFS&version=1.1.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(7, xpath.getMatchingNodes("//ows:Get[contains(@xlink:href,'sf/PrimitiveGeoFeature/wfs')]", doc).getLength()); assertEquals(7, xpath.getMatchingNodes("//ows:Post[contains(@xlink:href,'sf/PrimitiveGeoFeature/wfs')]", doc).getLength()); //TODO: test with a non existing workspace } @Test public void testMetadataLinks() throws Exception { FeatureTypeInfo mpolys = getCatalog().getFeatureTypeByName(getLayerId(MockTestData.MPOLYGONS)); // a valid link whose metadata type needs tweaking MetadataLinkInfo ml1 = getCatalog().getFactory().createMetadataLink(); ml1.setMetadataType("ISO19115:2003"); ml1.setType("text/html"); ml1.setContent("http://www.geoserver.org"); mpolys.getMetadataLinks().add(ml1); // a valid one MetadataLinkInfo ml2 = getCatalog().getFactory().createMetadataLink(); ml2.setMetadataType("FGDC"); ml2.setType("text/html"); ml2.setContent("http://www.geoserver.org"); mpolys.getMetadataLinks().add(ml2); // an invalid one, not a valid type MetadataLinkInfo ml3 = getCatalog().getFactory().createMetadataLink(); ml3.setMetadataType("other"); ml3.setType("text/html"); ml3.setContent("http://www.geoserver.org"); mpolys.getMetadataLinks().add(ml3); // an invalid one, not a valid format MetadataLinkInfo ml4 = getCatalog().getFactory().createMetadataLink(); ml4.setMetadataType("FGDC"); ml4.setType("application/zip"); ml4.setContent("http://www.geoserver.org"); mpolys.getMetadataLinks().add(ml4); getCatalog().save(mpolys); Document doc = getAsDOM("wfs?service=WFS&version=1.1.0&request=getCapabilities"); // print(doc); XpathEngine xpath = XMLUnit.newXpathEngine(); assertEquals(2, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL", doc).getLength()); assertEquals(2, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[@format='text/html']", doc).getLength()); assertEquals(1, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[@type='19115']", doc).getLength()); assertEquals(1, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[@type='FGDC']", doc).getLength()); assertEquals(2, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[text() = 'http://www.geoserver.org']", doc).getLength()); } @Test public void testMetadataLinksTransormToProxyBaseURL() throws Exception { FeatureTypeInfo mpolys = getCatalog().getFeatureTypeByName(getLayerId(MockTestData.MPOLYGONS)); // a valid link whose metadata type needs tweaking MetadataLinkInfo ml1 = getCatalog().getFactory().createMetadataLink(); ml1.setMetadataType("ISO19115:2003"); ml1.setType("text/html"); ml1.setContent("/metadata?key=value"); mpolys.getMetadataLinks().add(ml1); // a valid one MetadataLinkInfo ml2 = getCatalog().getFactory().createMetadataLink(); ml2.setMetadataType("FGDC"); ml2.setType("text/html"); ml2.setContent("/metadata?key=value"); mpolys.getMetadataLinks().add(ml2); // an invalid one, not a valid type MetadataLinkInfo ml3 = getCatalog().getFactory().createMetadataLink(); ml3.setMetadataType("other"); ml3.setType("text/html"); ml3.setContent("/metadata?key=value"); mpolys.getMetadataLinks().add(ml3); // an invalid one, not a valid format MetadataLinkInfo ml4 = getCatalog().getFactory().createMetadataLink(); ml4.setMetadataType("FGDC"); ml4.setType("application/zip"); ml4.setContent("/metadata?key=value"); mpolys.getMetadataLinks().add(ml4); getCatalog().save(mpolys); String proxyBaseUrl = getGeoServer().getGlobal().getSettings().getProxyBaseUrl(); Document doc = getAsDOM("wfs?service=WFS&version=1.1.0&request=getCapabilities"); XpathEngine xpath = XMLUnit.newXpathEngine(); assertEquals(2, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL", doc).getLength()); assertEquals(2, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[@format='text/html']", doc).getLength()); assertEquals(1, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[@type='19115']", doc).getLength()); assertEquals(1, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[@type='FGDC']", doc).getLength()); assertEquals(2, xpath.getMatchingNodes("//wfs:FeatureType[wfs:Name='cgf:MPolygons']/wfs:MetadataURL[text() = '" + proxyBaseUrl + "/metadata?key=value']", doc).getLength()); } @Test public void testOtherSRS() throws Exception { WFSInfo wfs = getGeoServer().getService(WFSInfo.class); wfs.getSRS().add("EPSG:4326"); // this one corresponds to the native one, should not be generated wfs.getSRS().add("EPSG:3857"); wfs.getSRS().add("EPSG:3003"); try { getGeoServer().save(wfs); // perform get caps Document doc = getAsDOM("wfs?service=WFS&version=1.1.0&request=getCapabilities"); // for each enabled type, check we added the otherSRS final List<FeatureTypeInfo> enabledTypes = getCatalog().getFeatureTypes(); for (Iterator<FeatureTypeInfo> it = enabledTypes.iterator(); it.hasNext();) { FeatureTypeInfo ft = it.next(); if (ft.enabled()) { String prefixedName = ft.prefixedName(); String base = "/wfs:WFS_Capabilities/wfs:FeatureTypeList/" + "wfs:FeatureType[wfs:Name =\"" + prefixedName + "\"]"; XMLAssert.assertXpathExists(base, doc); // we generate the other SRS only if it's not equal to native boolean wgs84Native = "EPSG:4326".equals(ft.getSRS()); if(wgs84Native) { XMLAssert.assertXpathEvaluatesTo("2", "count(" + base + "/wfs:OtherSRS)", doc); } else { XMLAssert.assertXpathEvaluatesTo("3", "count(" + base + "/wfs:OtherSRS)", doc); XMLAssert.assertXpathExists(base + "[wfs:OtherSRS = 'urn:x-ogc:def:crs:EPSG:4326']", doc); } XMLAssert.assertXpathExists(base + "[wfs:OtherSRS = 'urn:x-ogc:def:crs:EPSG:3003']", doc); XMLAssert.assertXpathExists(base + "[wfs:OtherSRS = 'urn:x-ogc:def:crs:EPSG:3857']", doc); } } } finally { wfs.getSRS().clear(); getGeoServer().save(wfs); } } @Test public void testOtherSRSSingleTypeOverride() throws Exception { WFSInfo wfs = getGeoServer().getService(WFSInfo.class); wfs.getSRS().add("EPSG:4326"); // this one corresponds to the native one, should not be generated wfs.getSRS().add("EPSG:3857"); wfs.getSRS().add("EPSG:3003"); String polygonsName = getLayerId(MockData.POLYGONS); FeatureTypeInfo polygons = getCatalog().getFeatureTypeByName(polygonsName); polygons.getResponseSRS().add("EPSG:32632"); polygons.setOverridingServiceSRS(true); try { getGeoServer().save(wfs); getCatalog().save(polygons); // check for this layer we have a different list Document doc = getAsDOM("wfs?service=WFS&version=1.1.0&request=getCapabilities"); String base = "/wfs:WFS_Capabilities/wfs:FeatureTypeList/" + "wfs:FeatureType[wfs:Name =\"" + polygonsName + "\"]"; XMLAssert.assertXpathExists(base, doc); XMLAssert.assertXpathEvaluatesTo("1", "count(" + base + "/wfs:OtherSRS)", doc); XMLAssert.assertXpathExists(base + "[wfs:OtherSRS = 'urn:x-ogc:def:crs:EPSG:32632']", doc); } finally { wfs.getSRS().clear(); getGeoServer().save(wfs); polygons.setOverridingServiceSRS(false); polygons.getResponseSRS().clear(); getCatalog().save(polygons); } } }