/* (c) 2014 - 2016 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.wms.wms_1_3; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo; import java.net.URL; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; import org.custommonkey.xmlunit.NamespaceContext; import org.custommonkey.xmlunit.SimpleNamespaceContext; import org.custommonkey.xmlunit.XMLUnit; import org.custommonkey.xmlunit.XpathEngine; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.DataStoreInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.MetadataLinkInfo; import org.geoserver.catalog.ResourceInfo; import org.geoserver.config.GeoServerInfo; import org.geoserver.data.test.MockData; import org.geoserver.data.test.SystemTestData; import org.geoserver.wms.WMSTestSupport; import org.geotools.xml.XML; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.ls.DOMImplementationLS; import org.w3c.dom.ls.LSInput; import org.w3c.dom.ls.LSResourceResolver; import org.xml.sax.SAXException; import org.springframework.mock.web.MockHttpServletResponse; /** * WMS 1.3 GetCapabilities system tests, following clauses in section 7.2 of <a * href="http://portal.opengeospatial.org/files/?artifact_id=14416">OGC document 06-042, OpenGIS Web * Map Service (WMS) Implementation Specification</a> as requirements specification. * * <p> * These are system tests in the sense that they verify specific system requirements as stated in * the various specification clauses. Yet they base on the same integration testing framework * established for other GeoServer tests in order to be able of mocking up a given configuration and * hence not needing a fully functional instance running inside a servlet container in order to do * some minimal system testing. * </p> * <p> * For tests that do not check adherence to specific spec clauses but that verify integration * aspects under different configuration situations use {@link CapabilitiesIntegrationTest} instead. * </p> * * @author Gabriel Roldan * */ public class CapabilitiesSystemTest extends WMSTestSupport { @Override protected void setUpTestData(SystemTestData testData) throws Exception { super.setUpTestData(testData); testData.setUpDefaultRasterLayers(); } @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"); NamespaceContext ctx = new SimpleNamespaceContext(namespaces); XMLUnit.setXpathNamespaceContext(ctx); GeoServerInfo global = getGeoServer().getGlobal(); global.getSettings().setProxyBaseUrl("src/test/resources/geoserver"); getGeoServer().save(global); LayerInfo layer = getCatalog().getLayerByName(MockData.POINTS.getLocalPart()); MetadataLinkInfo mdlink = getCatalog().getFactory().createMetadataLink(); mdlink.setMetadataType("FGDC"); mdlink.setContent("http://geoserver.org"); mdlink.setType("text/xml"); ResourceInfo resource = layer.getResource(); resource.getMetadataLinks().add(mdlink); getCatalog().save(resource); Catalog catalog = getCatalog(); DataStoreInfo info =catalog.getDataStoreByName(MockData.SF_PREFIX); info.setEnabled(false); catalog.save(info); } /** * As for section 7.2.4.1, ensures the GeCapabilities document validates against its schema */ @Test public void testValidateCapabilitiesXML() throws Exception { final Document dom = getAsDOM("ows?service=WMS&version=1.3.0&request=GetCapabilities"); SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); URL schemaLocation = getClass().getResource( "/schemas/wms/1.3.0/capabilities_1_3_0.xsd"); factory.setResourceResolver(new LSResourceResolver() { public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) { if(namespaceURI.equals("http://www.w3.org/1999/xlink")) { try { LSInput input = ((DOMImplementationLS)dom.getImplementation()).createLSInput(); URL xlink = getClass().getResource("/schemas/xlink/1999/xlink.xsd"); systemId = xlink.toURI().toASCIIString(); input.setPublicId(publicId); input.setSystemId(systemId); return input; } catch(Exception e) { return null; } } else if(XML.NAMESPACE.equals(namespaceURI)) { try { LSInput input = ((DOMImplementationLS)dom.getImplementation()).createLSInput(); URL xml = XML.class.getResource("xml.xsd"); systemId = xml.toURI().toASCIIString(); input.setPublicId(publicId); input.setSystemId(systemId); return input; } catch(Exception e) { return null; } } else { return null; } } }); Schema schema = factory.newSchema(schemaLocation); Validator validator = schema.newValidator(); Source source = new DOMSource(dom); try { validator.validate(source); assertTrue(true); } catch (SAXException ex) { LOGGER.log(Level.WARNING, "WMS 1.3.0 capabilities validation error", ex); print(dom); fail("WMS 1.3.0 capabilities validation error: " + ex.getMessage()); } } /** * Tests that GeoServer performs the server side of version number negotiation as defined in * section 6.2.4 * <p> * This tests assumes the only versions supported are 1.1.1 and 1.3.0, and shall be modified * accordingly whenever support for another version is added, or support for one of the existing * versions is removed * </p> * */ @Test public void testRequestVersionNumberNegotiation() throws Exception { Document dom; /* * In response to a GetCapabilities request (for which the VERSION parameter is optional) * that does not specify a version number, the server shall respond with the highest version * it supports. */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities"); assertXpathEvaluatesTo("1.3.0", "/wms:WMS_Capabilities/@version", dom); /* * A specific version is requested, the server responds with that specific version iif * supported */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.1.1"); assertXpathEvaluatesTo("1.1.1", "/WMT_MS_Capabilities/@version", dom); dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.3.0"); assertXpathEvaluatesTo("1.3.0", "/wms:WMS_Capabilities/@version", dom); /* * If a version unknown to the server and higher than the lowest supported version is * requested, the server shall send the highest version it supports that is less than the * requested version. */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.1.2"); assertXpathEvaluatesTo("1.1.1", "/WMT_MS_Capabilities/@version", dom); dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.4.0"); assertXpathEvaluatesTo("1.3.0", "/wms:WMS_Capabilities/@version", dom); /* * If a version lower than any of those known to the server is requested, then the server * shall send the lowest version it supports. */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.0.0"); assertXpathEvaluatesTo("1.1.1", "/WMT_MS_Capabilities/@version", dom); } /** * Section 7.2.3.1, FORMAT is an optional parameter, all services shall support {@code text/xml} * , if a non supported format is requested, the default {@code text/xml} representation shall * be returned. The response Content-Type header shall also be {@code text/xml} */ @Test public void testRequestOptionalFormatParameter() throws Exception { MockHttpServletResponse response; String path = "ows?service=WMS&request=GetCapabilities&version=1.3.0"; response = getAsServletResponse(path); assertEquals("WMS_Capabilities", getAsDOM(path).getDocumentElement().getNodeName()); assertEquals("text/xml", response.getContentType()); path = "ows?service=WMS&request=GetCapabilities&version=1.3.0&format=text/xml"; response = getAsServletResponse(path); assertEquals("WMS_Capabilities", getAsDOM(path).getDocumentElement().getNodeName()); assertEquals("text/xml", response.getContentType()); path = "ows?service=WMS&request=GetCapabilities&version=1.3.0&format=application/unsupported"; response = getAsServletResponse(path); assertEquals("WMS_Capabilities", getAsDOM(path).getDocumentElement().getNodeName()); assertEquals("text/xml", response.getContentType()); } /** * Section 7.2.3.3, SERVICE is a mandatory parameter with fixed value {@code WMS} */ @Test public void testRequestMandatoryServiceParameter() throws Exception { Document dom = getAsDOM("ows?request=GetCapabilities&version=1.3.0"); print(dom); assertXpathEvaluatesTo("InvalidParameterValue", "/ows:ExceptionReport/ows:Exception/@exceptionCode", dom); } /** * Section 7.2.3.4, REQUEST is a mandatory parameter with fixed value {@code GetCapabilities} * (case insensitive for GeoServer, spec doesn't tell) */ @Test public void testRequestMandatoryRequestParameter() throws Exception { Document dom = getAsDOM("ows?request=GetCapabilities&version=1.3.0"); // print(dom); assertXpathEvaluatesTo("InvalidParameterValue", "/ows:ExceptionReport/ows:Exception/@exceptionCode", dom); } /** * Section 7.2.3.5, table 4: response handling if client specifies UPDATESEQUENCE * <p> * This test assumes GeoServer delivers numeric (integer) {@code updateSequence} values * </p> */ @Test public void testRequestUpdateSequence() throws Exception { Document dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.3.0"); final XpathEngine xpath = XMLUnit.newXpathEngine(); final String locationPath = "/wms:WMS_Capabilities/@updateSequence"; final String updateSeq = xpath.evaluate(locationPath, dom); final int currUpdateSeq = Integer.parseInt(updateSeq); /* * Client: none, Server: any, response: current */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.3.0"); assertXpathEvaluatesTo(updateSeq, locationPath, dom); /* * Client: any, Server: none, response: current. Can't implement this as a test cause * GeoServer will always have an internal update sequence */ // can't test /* * Client: equal, Server: equal, response: exception code=CurrentUpdateSequence */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.3.0&updateSequence=" + updateSeq); print(dom); assertXpathEvaluatesTo("1.3.0", "/ogc:ServiceExceptionReport/@version", dom); assertXpathEvaluatesTo("CurrentUpdateSequence", "/ogc:ServiceExceptionReport/ogc:ServiceException/@code", dom); /* * Client: lower, Server: higher, response: current */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.3.0&updateSequence=" + (currUpdateSeq - 1)); assertXpathEvaluatesTo(updateSeq, locationPath, dom); /* * Client: higher, Server: lower, response: exception code=InvalidUpdateSequence */ dom = getAsDOM("ows?service=WMS&request=GetCapabilities&version=1.3.0&updateSequence=" + (currUpdateSeq + 1)); assertXpathEvaluatesTo("InvalidUpdateSequence", "/ogc:ServiceExceptionReport/ogc:ServiceException/@code", dom); } }