/* (c) 2016 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.gwc.wmts;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.geoserver.catalog.*;
import org.geoserver.catalog.impl.DimensionInfoImpl;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.gwc.wmts.dimensions.Dimension;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.w3c.dom.Document;
import java.util.HashMap;
import java.util.Map;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* Tests that perform requests again the multidimensional extension and check the results
* for the main four operations: GetCapabilities, DescribeDomains, GetHistogram and GetFewature
*/
public class MultiDimensionalExtensionTest extends TestsSupport {
// xpath engine that will be used to check XML content
private static XpathEngine xpath;
{
// registering namespaces for the xpath engine
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("ows", "http://www.opengis.net/ows/1.1");
namespaces.put("wmts", "http://www.opengis.net/wmts/1.0");
namespaces.put("md", "http://demo.geo-solutions.it/share/wmts-multidim/wmts_multi_dimensional.xsd");
namespaces.put("gml", "http://www.opengis.net/gml");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
xpath = XMLUnit.newXpathEngine();
}
@Override
protected void afterSetup(SystemTestData testData) {
// registering elevation and time dimensions for a raster
CoverageInfo rasterInfo = getCatalog().getCoverageByName(RASTER_ELEVATION_TIME.getLocalPart());
registerLayerDimension(rasterInfo, ResourceInfo.ELEVATION, null, DimensionPresentation.LIST, minimumValue());
registerLayerDimension(rasterInfo, ResourceInfo.TIME, null, DimensionPresentation.CONTINUOUS_INTERVAL, minimumValue());
// registering elevation and time dimensions for a vector
FeatureTypeInfo vectorInfo = getCatalog().getFeatureTypeByName(VECTOR_ELEVATION_TIME.getLocalPart());
registerLayerDimension(vectorInfo, ResourceInfo.ELEVATION, "startElevation", DimensionPresentation.CONTINUOUS_INTERVAL, minimumValue());
registerLayerDimension(vectorInfo, ResourceInfo.TIME, "startTime", DimensionPresentation.LIST, minimumValue());
}
@Test
public void testGetCapabilitiesOperation() throws Exception {
// perform the get capabilities request
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?request=GetCapabilities");
Document result = getResultAsDocument(response, "application/vnd.ogc.wms_xml");
// check raster layer dimensions
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension", "4");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[ows:Identifier='elevation']", "2");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[ows:Identifier='time']", "2");
// check raster elevation dimension
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Default='0.0']", "1");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Value='0']", "1");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Value='100']", "1");
// check raster time dimension
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Default='0.0']", "1");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Value='2008-10-31T00:00:00.000Z--2008-11-01T00:00:00.000Z']", "1");
// check vector elevation dimension
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Default='1.0']", "1");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Value='1.0--2.0']", "1");
// check vector time dimension
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Default='2012-02-11T00:00:00Z']", "1");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Value='2012-02-11T00:00:00.000Z']", "1");
checkXpathCount(result, "/wmts:Contents/wmts:Layer/wmts:Dimension[wmts:Value='2012-02-12T00:00:00.000Z']", "1");
}
@Test
public void testRasterDescribeDomainsOperation() throws Exception {
// perform the get describe domains operation request
String queryRequest = String.format("request=DescribeDomains&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
RASTER_ELEVATION_TIME.getPrefix() + ":" + RASTER_ELEVATION_TIME.getLocalPart());
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check that we have two domains
checkXpathCount(result, "/md:Domains/md:DimensionDomain", "2");
// both domains contain two elements
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Size='2']", "2");
// check the elevation domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='elevation']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='0,100']", "1");
// check the time domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='time']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='2008-10-31T00:00:00.000Z--2008-11-01T00:00:00.000Z']", "1");
// check the space domain
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@CRS='EPSG:4326']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@minx='0.23722068851276978']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@miny='40.562080748421806']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxx='14.592757149389236']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxy='44.55808294568743']", "1");
}
@Test
public void testVectorDescribeDomainsOperation() throws Exception {
// perform the get describe domains operation request
String queryRequest = String.format("request=DescribeDomains&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
VECTOR_ELEVATION_TIME.getPrefix() + ":" + VECTOR_ELEVATION_TIME.getLocalPart());
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check that we have two domains
checkXpathCount(result, "/md:Domains/md:DimensionDomain", "2");
// both domains contain two elements
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Size='2']", "2");
// check the elevation domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='elevation']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='1.0--2.0']", "1");
// check the time domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='time']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='2012-02-11T00:00:00.000Z,2012-02-12T00:00:00.000Z']", "1");
// check the space domain
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@CRS='EPSG:4326']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@minx='-180.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@miny='-90.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxx='180.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxy='90.0']", "1");
}
@Test
public void testRasterDescribeDomainsOperationWithElevationFilter() throws Exception {
// perform the get describe domains operation request filter elevations that are equal to 100.0
String queryRequest = String.format("request=DescribeDomains&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
RASTER_ELEVATION_TIME.getPrefix() + ":" + RASTER_ELEVATION_TIME.getLocalPart() + "&elevation=100");
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check that we have two domains
checkXpathCount(result, "/md:Domains/md:DimensionDomain", "2");
// check the elevation domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='elevation']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='100']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Size='1']", "1");
// check the time domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='time']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='2008-10-31T00:00:00.000Z--2008-11-01T00:00:00.000Z']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Size='2']", "1");
// check the space domain
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@CRS='EPSG:4326']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@minx='0.23722068851276978']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@miny='40.562080748421806']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxx='14.592757149389236']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxy='44.55808294568743']", "1");
}
@Test
public void testVectorDescribeDomainsOperationWithTimeFilterNoResults() throws Exception {
// perform the get describe domains operation request filter elevations that are equal to 100.0
String queryRequest = String.format("request=DescribeDomains&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
VECTOR_ELEVATION_TIME.getPrefix() + ":" + VECTOR_ELEVATION_TIME.getLocalPart() + "&time=1980-10-31T00:00:00.000Z");
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check that we have two domains
checkXpathCount(result, "/md:Domains/md:DimensionDomain", "2");
// the domain should not contain any values
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Size='0']", "2");
// check the space domain
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@CRS='EPSG:4326']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@minx='0.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@miny='0.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxx='-1.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxy='-1.0']", "1");
}
@Test
public void testRasterDescribeDomainsOperationWithBoundingBoxNoResultsFilter() throws Exception {
// perform the get describe domains operation with a spatial restriction
String queryRequest = String.format("request=DescribeDomains&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
RASTER_ELEVATION_TIME.getPrefix() + ":" + RASTER_ELEVATION_TIME.getLocalPart() + "&bbox=5,5,6,6");
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check that we have two domains
checkXpathCount(result, "/md:Domains/md:DimensionDomain", "2");
// check the space domain
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@CRS='EPSG:4326']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@minx='0.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@miny='0.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxx='-1.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxy='-1.0']", "1");
// the domain should not contain any values
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Size='0']", "2");
}
@Test
public void testRasterDescribeDomainsOperationWithBoundingAndWrongTileMatrixSet() throws Exception {
// perform the get describe domains operation with a spatial restriction and in invalid tile matrix set
String queryRequest = String.format("request=DescribeDomains&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:XXXX",
RASTER_ELEVATION_TIME.getPrefix() + ":" + RASTER_ELEVATION_TIME.getLocalPart() + "&bbox=5,5,6,6");
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
// this request should fail because of the invalid tile matrix set
assertThat(response.getContentAsString(), containsString("Unknown grid set"));
assertThat(response.getStatus(), is(500));
}
@Test
public void testVectorDescribeDomainsOperationWithBoundingBoxFilter() throws Exception {
// perform the get describe domains operation with a spatial restriction
String queryRequest = String.format("request=DescribeDomains&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
VECTOR_ELEVATION_TIME.getPrefix() + ":" + VECTOR_ELEVATION_TIME.getLocalPart() + "&bbox=-180,-90,180,90");
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check the space domain
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@CRS='EPSG:4326']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@minx='-180.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@miny='-90.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxx='180.0']", "1");
checkXpathCount(result, "/md:Domains/md:SpaceDomain/md:BoundingBox[@maxy='90.0']", "1");
// check that we have two domains
checkXpathCount(result, "/md:Domains/md:DimensionDomain", "2");
// both domains contain two elements
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Size='2']", "2");
// check the elevation domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='elevation']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='1.0--2.0']", "1");
// check the time domain
checkXpathCount(result, "/md:Domains/md:DimensionDomain[ows:Identifier='time']", "1");
checkXpathCount(result, "/md:Domains/md:DimensionDomain[md:Domain='2012-02-11T00:00:00.000Z,2012-02-12T00:00:00.000Z']", "1");
}
@Test
public void testRasterGetHistogramOperationForElevation() throws Exception {
// perform the get histogram operation request
String queryRequest = String.format("request=GetHistogram&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326&histogram=elevation&resolution=25",
RASTER_ELEVATION_TIME.getPrefix() + ":" + RASTER_ELEVATION_TIME.getLocalPart());
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check the returned histogram
checkXpathCount(result, "/md:Histogram[ows:Identifier='elevation']", "1");
checkXpathCount(result, "/md:Histogram[md:Domain='0.0/100.0/25.0']", "1");
checkXpathCount(result, "/md:Histogram[md:Values='2,0,0,2']", "1");
}
@Test
public void testVectorGetHistogramOperationForTime() throws Exception {
// perform the get histogram operation request
String queryRequest = String.format("request=GetHistogram&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326&histogram=time&resolution=P1M",
VECTOR_ELEVATION_TIME.getPrefix() + ":" + VECTOR_ELEVATION_TIME.getLocalPart());
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response);
// check the returned histogram
checkXpathCount(result, "/md:Histogram[ows:Identifier='time']", "1");
checkXpathCount(result, "/md:Histogram[md:Domain='2012-02-11T00:00:00.000Z/2012-02-12T00:00:00.000Z/P1M']", "1");
checkXpathCount(result, "/md:Histogram[md:Values='3']", "1");
}
@Test
public void testRasterGetFeatureOperation() throws Exception {
// perform the get feature operation request
String queryRequest = String.format("request=GetFeature&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
RASTER_ELEVATION_TIME.getPrefix() + ":" + RASTER_ELEVATION_TIME.getLocalPart());
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response, "text/xml; subtype=gml/3.1.1");
// check the returned features
checkXpathCount(result, "/wmts:feature", "4");
checkXpathCount(result, "/wmts:feature/wmts:footprint/gml:MultiPolygon", "4");
checkXpathCount(result, "/wmts:feature[wmts:dimension='0']", "2");
checkXpathCount(result, "/wmts:feature[wmts:dimension='100']", "2");
checkXpathCount(result, "/wmts:feature[wmts:dimension='2008-10-31T00:00:00.000Z']", "2");
checkXpathCount(result, "/wmts:feature[wmts:dimension='2008-11-01T00:00:00.000Z']", "2");
}
@Test
public void testRasterGetFeatureOperationWithBoundingBoxFilterNoResults() throws Exception {
// perform the get feature operation request
String queryRequest = String.format("request=GetFeature&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
RASTER_ELEVATION_TIME.getPrefix() + ":" + RASTER_ELEVATION_TIME.getLocalPart() + "&bbox=-1,-1,0,0");
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response, "text/xml; subtype=gml/3.1.1");
// check the no features were returned
checkXpathCount(result, "/wmts:feature", "0");
}
@Test
public void testVectorGetFeatureOperation() throws Exception {
// perform the get histogram operation request
String queryRequest = String.format("request=GetFeature&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
RASTER_ELEVATION_TIME.getPrefix() + ":" + VECTOR_ELEVATION_TIME.getLocalPart());
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response, "text/xml; subtype=gml/3.1.1");
// check the returned features
checkXpathCount(result, "/wmts:feature", "3");
checkXpathCount(result, "/wmts:feature/wmts:footprint/gml:Polygon", "3");
checkXpathCount(result, "/wmts:feature[wmts:dimension='1.0']", "2");
checkXpathCount(result, "/wmts:feature[wmts:dimension='2.0']", "1");
checkXpathCount(result, "/wmts:feature[wmts:dimension='2012-02-11T00:00:00.000Z']", "2");
checkXpathCount(result, "/wmts:feature[wmts:dimension='2012-02-12T00:00:00.000Z']", "1");
}
@Test
public void testVectorGetFeatureOperationWithTimeFilter() throws Exception {
// perform the get histogram operation request
String queryRequest = String.format("request=GetFeature&Version=1.0.0&Layer=%s&TileMatrixSet=EPSG:4326",
RASTER_ELEVATION_TIME.getPrefix() + ":" + VECTOR_ELEVATION_TIME.getLocalPart()
+ "&time=2012-02-10T00:00:00.000Z/2012-02-11T00:00:00.000Z");
MockHttpServletResponse response = getAsServletResponse("gwc/service/wmts?" + queryRequest);
Document result = getResultAsDocument(response, "text/xml; subtype=gml/3.1.1");
// check the filtered returned features
checkXpathCount(result, "/wmts:feature", "2");
checkXpathCount(result, "/wmts:feature/wmts:footprint/gml:Polygon", "2");
checkXpathCount(result, "/wmts:feature[wmts:dimension='1.0']", "2");
checkXpathCount(result, "/wmts:feature[wmts:dimension='2012-02-11T00:00:00.000Z']", "2");
}
/**
* Helper method that will create a default value strategy, minimum value in this case.
*/
private DimensionDefaultValueSetting minimumValue() {
DimensionDefaultValueSetting defaultValueSetting = new DimensionDefaultValueSetting();
defaultValueSetting.setStrategyType(DimensionDefaultValueSetting.Strategy.MINIMUM);
return defaultValueSetting;
}
/**
* Helper method that will register a dimension for some layer.
*/
private void registerLayerDimension(ResourceInfo info, String dimensionName, String attributeName,
DimensionPresentation presentation, DimensionDefaultValueSetting defaultValue) {
DimensionInfo dimension = new DimensionInfoImpl();
dimension.setEnabled(true);
dimension.setPresentation(presentation);
dimension.setDefaultValue(defaultValue);
dimension.setAttribute(attributeName);
info.getMetadata().put(dimensionName, dimension);
getCatalog().save(info);
}
/**
* Helper method that simply extracts the result of a request to a string and builds a document.
* Also checks that the content type is 'text/xml'.
*/
private Document getResultAsDocument(MockHttpServletResponse response) throws Exception {
return getResultAsDocument(response, "text/xml");
}
/**
* Helper method that simply extracts the result of a request to a string and build a document.
* Also checks the content type of the response.
*/
private Document getResultAsDocument(MockHttpServletResponse response, String contentType) throws Exception {
String result = response.getContentAsString();
assertThat(response.getStatus(), is(200));
assertThat(response.getContentType(), is(contentType));
return XMLUnit.buildTestDocument(result);
}
/**
* Helper method that perform a XPATH count and check the result.
*/
private void checkXpathCount(Document result, String path, String count) throws Exception {
String finalPath = String.format("count(/%s)", path);
assertThat(xpath.evaluate(finalPath, result), is(count));
}
@Override
protected Dimension buildDimension(DimensionInfo dimensionInfo) {
return null;
}
}