package org.geowebcache.service.wmts;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.Matchers.is;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.hasEntry;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import junit.framework.TestCase;
import org.apache.commons.collections.map.CaseInsensitiveMap;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.custommonkey.xmlunit.Validator;
import org.geowebcache.GeoWebCacheDispatcher;
import org.geowebcache.GeoWebCacheException;
import org.geowebcache.config.XMLGridSubset;
import org.geowebcache.config.legends.LegendInfo;
import org.geowebcache.config.legends.LegendInfoBuilder;
import org.geowebcache.config.meta.ServiceContact;
import org.geowebcache.config.meta.ServiceInformation;
import org.geowebcache.config.meta.ServiceProvider;
import org.geowebcache.conveyor.Conveyor;
import org.geowebcache.conveyor.ConveyorTile;
import org.geowebcache.filter.parameters.ParameterFilter;
import org.geowebcache.filter.parameters.StringParameterFilter;
import org.geowebcache.grid.BoundingBox;
import org.geowebcache.grid.GridSet;
import org.geowebcache.grid.GridSetBroker;
import org.geowebcache.grid.GridSubset;
import org.geowebcache.grid.SRS;
import org.geowebcache.io.XMLBuilder;
import org.geowebcache.layer.TileLayer;
import org.geowebcache.layer.TileLayerDispatcher;
import org.geowebcache.layer.meta.MetadataURL;
import org.geowebcache.mime.MimeType;
import org.geowebcache.service.OWSException;
import org.geowebcache.stats.RuntimeStats;
import org.geowebcache.storage.StorageBroker;
import org.geowebcache.util.NullURLMangler;
import org.springframework.mock.web.MockHttpServletResponse;
import org.w3c.dom.Document;
public class WMTSServiceTest extends TestCase {
private WMTSService service;
private StorageBroker sb;
private TileLayerDispatcher tld;
private GridSetBroker gridsetBroker;
protected void setUp() throws Exception {
sb = mock(StorageBroker.class);
tld = mock(TileLayerDispatcher.class);
gridsetBroker = new GridSetBroker(true, true);
}
private TileLayer mockTileLayer(String layerName, List<String> gridSetNames,
List<ParameterFilter> parameterFilters) throws Exception {
return mockTileLayer(layerName, gridSetNames, parameterFilters, true);
}
private TileLayer mockTileLayer(String layerName, List<String> gridSetNames, List<ParameterFilter> parameterFilters, boolean advertised) throws Exception {
TileLayer tileLayer = mock(TileLayer.class);
when(tld.getTileLayer(eq(layerName))).thenReturn(tileLayer);
when(tileLayer.getName()).thenReturn(layerName);
when(tileLayer.isEnabled()).thenReturn(true);
when(tileLayer.isAdvertised()).thenReturn(advertised);
final MimeType mimeType1 = MimeType.createFromFormat("image/png");
final MimeType mimeType2 = MimeType.createFromFormat("image/jpeg");
when(tileLayer.getMimeTypes()).thenReturn(Arrays.asList(mimeType1, mimeType2));
Map<String, GridSubset> subsets = new HashMap<String, GridSubset>();
Map<SRS, List<GridSubset>> bySrs = new HashMap<SRS, List<GridSubset>>();
GridSetBroker broker = gridsetBroker;
for (String gsetName : gridSetNames) {
GridSet gridSet = broker.get(gsetName);
XMLGridSubset xmlGridSubset = new XMLGridSubset();
String gridSetName = gridSet.getName();
xmlGridSubset.setGridSetName(gridSetName);
GridSubset gridSubSet = xmlGridSubset.getGridSubSet(broker);
subsets.put(gsetName, gridSubSet);
List<GridSubset> list = bySrs.get(gridSet.getSrs());
if (list == null) {
list = new ArrayList<GridSubset>();
bySrs.put(gridSet.getSrs(), list);
}
list.add(gridSubSet);
when(tileLayer.getGridSubset(eq(gsetName))).thenReturn(gridSubSet);
}
for (SRS srs : bySrs.keySet()) {
List<GridSubset> list = bySrs.get(srs);
when(tileLayer.getGridSubsetsForSRS(eq(srs))).thenReturn(list);
}
when(tileLayer.getGridSubsets()).thenReturn(subsets.keySet());
when(tileLayer.getParameterFilters()).thenReturn(parameterFilters);
// sanity check
for (String gsetName : gridSetNames) {
assertTrue(tileLayer.getGridSubsets().contains(gsetName));
assertNotNull(tileLayer.getGridSubset(gsetName));
}
return tileLayer;
}
public void testGetCap() throws Exception {
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld,null , mock(RuntimeStats.class));
@SuppressWarnings("unchecked")
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{"WMTS"});
kvp.put("version", new String[]{"1.0.0"});
kvp.put("request", new String[]{"GetCapabilities"});
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
{
List<String> gridSetNames = Arrays.asList("GlobalCRS84Pixel", "GlobalCRS84Scale","EPSG:4326");
TileLayer tileLayer = mockTileLayer("mockLayer", gridSetNames, Collections.<ParameterFilter>emptyList());
TileLayer tileLayerUn = mockTileLayer("mockLayerUnadv", gridSetNames, Collections.<ParameterFilter>emptyList(), false);
when(tld.getLayerList()).thenReturn(Arrays.asList(tileLayer, tileLayerUn));
// add styles
StringParameterFilter styles = new StringParameterFilter();
styles.setKey("STYLES");
styles.setValues(Arrays.asList("style-a", "style-b"));
when(tileLayer.getParameterFilters()).thenReturn(Collections.singletonList(styles));
// add legend info for style-a
TileLayer.LegendInfo legendInfo1 = TileLayer.createLegendInfo();
legendInfo1.id = "styla-a-legend";
legendInfo1.width = 250;
legendInfo1.height = 500;
legendInfo1.format = "image/jpeg";
legendInfo1.legendUrl = "https://some-url?some-parameter=value1&another-parameter=value2";
when(tileLayer.getLegendsInfo()).thenReturn(Collections.singletonMap("style-a", legendInfo1));
// add legend info for style-b
LegendInfo legendInfo2 = new LegendInfoBuilder()
.withStyleName("styla-b-legend")
.withWidth(125)
.withHeight(130)
.withFormat("image/png")
.withCompleteUrl("https://some-url?some-parameter=value3&another-parameter=value4")
.withMinScale(5000D)
.withMaxScale(10000D)
.build();
when(tileLayer.getLayerLegendsInfo()).thenReturn(Collections.singletonMap("style-b", legendInfo2));
// add some layer metadata
MetadataURL metadataURL = new MetadataURL("some-type", "some-format", new URL("http://localhost:8080/some-url"));
when(tileLayer.getMetadataURLs()).thenReturn(Collections.singletonList(metadataURL));
}
Conveyor conv = service.getConveyor(req, resp);
assertNotNull(conv);
final String layerName = conv.getLayerId();
assertNull(layerName);
assertEquals(Conveyor.RequestHandler.SERVICE,conv.reqHandler);
WMTSGetCapabilities wmsCap = new WMTSGetCapabilities(tld,gridsetBroker, conv.servletReq,"http://localhost:8080", "/service/wms", new NullURLMangler());
wmsCap.writeResponse(conv.servletResp,mock(RuntimeStats.class));
assertTrue(resp.containsHeader("content-disposition"));
assertEquals("inline;filename=wmts-getcapabilities.xml", resp.getHeader("content-disposition"));
// System.out.println(resp.getContentAsString());
String result = resp.getContentAsString();
// Ensure the advertised Layer is contained and the unadvertised not
assertTrue(result.contains("mockLayer"));
assertFalse(result.contains("mockLayerUnadv"));
//Validator validator = new Validator(result);
//validator.useXMLSchema(true);
//validator.assertIsValid();
Document doc = XMLUnit.buildTestDocument(result);
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");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
XpathEngine xpath = XMLUnit.newXpathEngine();
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer)", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer'])", doc));
assertEquals("2", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:Style/ows:Identifier)", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:Style[ows:Identifier='style-a'])", doc));
// checking that style-a has the correct legend url
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:Style[ows:Identifier='style-a']/wmts:LegendURL" +
"[@width='250'][@height='500'][@format='image/jpeg'][@xlink:href='https://some-url?some-parameter=value1&another-parameter=value2'])", doc));
// checking that style-b has the correct legend url
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:Style[ows:Identifier='style-b']/wmts:LegendURL" +
"[@width='125'][@height='130'][@format='image/png'][@minScaleDenominator='5000.0'][@maxScaleDenominator='10000.0']" +
"[@xlink:href='https://some-url?some-parameter=value3&another-parameter=value4'])", doc));
// checking that the layer has an associated metadata URL
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:MetadataURL[@type='some-type'][wmts:Format='some-format'])", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:MetadataURL[@type='some-type']" +
"/wmts:OnlineResource[@xlink:href='http://localhost:8080/some-url'])", doc));
}
public void testGetCapWithExtensions() throws Exception {
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld, null, mock(RuntimeStats.class));
@SuppressWarnings("unchecked")
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{"WMTS"});
kvp.put("version", new String[]{"1.0.0"});
kvp.put("request", new String[]{"GetCapabilities"});
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
List<String> gridSetNames = Arrays.asList("GlobalCRS84Pixel", "GlobalCRS84Scale","EPSG:4326");
TileLayer tileLayer = mockTileLayer("mockLayer", gridSetNames, Collections.<ParameterFilter>emptyList());
when(tld.getLayerList()).thenReturn(Collections.singletonList(tileLayer));
Conveyor conv = service.getConveyor(req, resp);
assertNotNull(conv);
assertEquals(Conveyor.RequestHandler.SERVICE, conv.reqHandler);
// setup a wmts extension
List<WMTSExtension> extensions = new ArrayList<>();
extensions.add(new WMTSExtension() {
@Override
public String[] getSchemaLocations() {
return new String[]{"name-space schema-location"};
}
@Override
public void registerNamespaces(XMLBuilder xml) throws IOException {
xml.attribute("xmlns:custom", "custom");
}
@Override
public void encodedOperationsMetadata(XMLBuilder xml) throws IOException {
xml.startElement("custom-metadata");
xml.endElement("custom-metadata");
}
@Override
public List<OperationMetadata> getExtraOperationsMetadata() throws IOException {
return Arrays.asList(new OperationMetadata("ExtraOperation1"),
new OperationMetadata("ExtraOperation2", "custom-url"));
}
@Override
public ServiceInformation getServiceInformation() {
ServiceInformation serviceInformation = new ServiceInformation();
serviceInformation.setTitle("custom-service");
return serviceInformation;
}
@Override
public Conveyor getConveyor(HttpServletRequest request, HttpServletResponse response, StorageBroker storageBroker) throws GeoWebCacheException, OWSException {
return null;
}
@Override
public boolean handleRequest(Conveyor conveyor) throws OWSException {
return false;
}
@Override
public void encodeLayer(XMLBuilder xmlBuilder, TileLayer tileLayer) throws IOException {
xmlBuilder.simpleElement("extra-layer-metadata", "metadatada", true);
}
});
extensions.add(new WMTSExtensionImpl() {
@Override
public ServiceInformation getServiceInformation() {
ServiceInformation serviceInformation = new ServiceInformation();
ServiceProvider serviceProvider = new ServiceProvider();
serviceProvider.setProviderName("custom-provider");
serviceInformation.setServiceProvider(serviceProvider);
ServiceContact contactInformation = new ServiceContact();
contactInformation.setPositionName("custom-position");
serviceProvider.setServiceContact(contactInformation);
return serviceInformation;
}
});
extensions.add(new WMTSExtensionImpl());
// perform the get capabilities request
WMTSGetCapabilities wmsCap = new WMTSGetCapabilities(tld, gridsetBroker, conv.servletReq, "http://localhost:8080", "/service/wmts",
new NullURLMangler(), extensions);
wmsCap.writeResponse(conv.servletResp, mock(RuntimeStats.class));
assertTrue(resp.containsHeader("content-disposition"));
assertEquals("inline;filename=wmts-getcapabilities.xml", resp.getHeader("content-disposition"));
String result = resp.getContentAsString();
assertTrue(result.contains("xmlns:custom=\"custom\""));
assertTrue(result.contains("name-space schema-location"));
// instantiate the xpath engine
Document doc = XMLUnit.buildTestDocument(result);
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");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
XpathEngine xpath = XMLUnit.newXpathEngine();
// checking that we have the service extra information
assertEquals("1", xpath.evaluate("count(//wmts:custom-metadata)", doc));
assertEquals("1", xpath.evaluate("count(//ows:ServiceIdentification[ows:Title='custom-service'])", doc));
assertEquals("1", xpath.evaluate("count(//ows:ServiceProvider[ows:ProviderName='custom-provider'])", doc));
assertEquals("1", xpath.evaluate("count(//ows:ServiceProvider/ows:ServiceContact[ows:PositionName='custom-position'])", doc));
// checking that the extra operations were encoded
assertEquals("1", xpath.evaluate("count(//ows:OperationsMetadata/ows:Operation[@name='ExtraOperation1'])", doc));
assertEquals("1", xpath.evaluate("count(//ows:OperationsMetadata/ows:Operation[@name='ExtraOperation1']" +
"/ows:DCP/ows:HTTP/ows:Get[@xlink:href='http://localhost:8080/service/wmts/service/wmts?'])", doc));
assertEquals("1", xpath.evaluate("count(//ows:OperationsMetadata/ows:Operation[@name='ExtraOperation2'])", doc));
assertEquals("1", xpath.evaluate("count(//ows:OperationsMetadata/ows:Operation[@name='ExtraOperation2']" +
"/ows:DCP/ows:HTTP/ows:Get[@xlink:href='custom-url?'])", doc));
// checking that layer extra metadata was encoded
xpath.evaluate("count(//wmts:Contents/wmts:Layer[wmts:extra-layer-metadata='metadatada'])", doc);
}
public void testGetCapOneWGS84BBox() throws Exception {
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld,null , mock(RuntimeStats.class));
@SuppressWarnings("unchecked")
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{"WMTS"});
kvp.put("version", new String[]{"1.0.0"});
kvp.put("request", new String[]{"GetCapabilities"});
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
{
List<String> gridSetNames = Arrays.asList("GlobalCRS84Pixel", "GlobalCRS84Scale","EPSG:4326", "EPSG:900913");
TileLayer tileLayer = mockTileLayer("mockLayer", gridSetNames, Collections.<ParameterFilter>emptyList());
TileLayer tileLayerUn = mockTileLayer("mockLayerUnadv", gridSetNames, Collections.<ParameterFilter>emptyList(), false);
when(tld.getLayerList()).thenReturn(Arrays.asList(tileLayer, tileLayerUn));
GridSubset wgs84Subset = mock(GridSubset.class);
when(wgs84Subset.getOriginalExtent()).thenReturn(new BoundingBox(-42d, -24d, 40d, 50d));
GridSubset googleSubset = mock(GridSubset.class);
when(googleSubset.getOriginalExtent()).thenReturn(new BoundingBox(1_000_000d, 2_000_000d, 1_000_000d, 2_000_000d));
when(tileLayer.getGridSubsetForSRS(SRS.getEPSG4326())).thenReturn(wgs84Subset);
when(tileLayer.getGridSubsetForSRS(SRS.getEPSG900913())).thenReturn(googleSubset);
}
Conveyor conv = service.getConveyor(req, resp);
assertNotNull(conv);
final String layerName = conv.getLayerId();
assertNull(layerName);
assertEquals(Conveyor.RequestHandler.SERVICE,conv.reqHandler);
WMTSGetCapabilities wmsCap = new WMTSGetCapabilities(tld,gridsetBroker, conv.servletReq,"http://localhost:8080", "/service/wms", new NullURLMangler());
wmsCap.writeResponse(conv.servletResp,mock(RuntimeStats.class));
assertTrue(resp.containsHeader("content-disposition"));
assertEquals("inline;filename=wmts-getcapabilities.xml", resp.getHeader("content-disposition"));
// System.out.println(resp.getContentAsString());
String result = resp.getContentAsString();
// Ensure the advertised Layer is contained and the unadvertised not
assertTrue(result.contains("mockLayer"));
assertFalse(result.contains("mockLayerUnadv"));
//Validator validator = new Validator(result);
//validator.useXMLSchema(true);
//validator.assertIsValid();
Document doc = XMLUnit.buildTestDocument(result);
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("ows", "http://www.opengis.net/ows/1.1");
namespaces.put("wmts", "http://www.opengis.net/wmts/1.0");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
XpathEngine xpath = XMLUnit.newXpathEngine();
assertEquals("1", xpath.evaluate("count(//ows:WGS84BoundingBox)", doc));
}
public void testGetCapUnboundedStyleFilter() throws Exception {
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld,null , mock(RuntimeStats.class));
@SuppressWarnings("unchecked")
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{"WMTS"});
kvp.put("version", new String[]{"1.0.0"});
kvp.put("request", new String[]{"GetCapabilities"});
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
{
List<String> gridSetNames = Arrays.asList("GlobalCRS84Pixel", "GlobalCRS84Scale","EPSG:4326");
ParameterFilter styleFilter = mock(ParameterFilter.class);
when(styleFilter.getKey()).thenReturn("STYLES");
when(styleFilter.getDefaultValue()).thenReturn("Foo");
when(styleFilter.getLegalValues()).thenReturn(null);
TileLayer tileLayer = mockTileLayer("mockLayer", gridSetNames, Collections.singletonList(styleFilter));
when(tld.getLayerList()).thenReturn(Arrays.asList(tileLayer));
}
Conveyor conv = service.getConveyor(req, resp);
assertNotNull(conv);
final String layerName = conv.getLayerId();
assertNull(layerName);
assertEquals(Conveyor.RequestHandler.SERVICE,conv.reqHandler);
WMTSGetCapabilities wmsCap = new WMTSGetCapabilities(tld,gridsetBroker, conv.servletReq,"http://localhost:8080", "/service/wms", new NullURLMangler());
wmsCap.writeResponse(conv.servletResp,mock(RuntimeStats.class));
assertTrue(resp.containsHeader("content-disposition"));
assertEquals("inline;filename=wmts-getcapabilities.xml", resp.getHeader("content-disposition"));
// System.out.println(resp.getContentAsString());
String result = resp.getContentAsString();
//Validator validator = new Validator(result);
//validator.useXMLSchema(true);
//validator.assertIsValid();
Document doc = XMLUnit.buildTestDocument(result);
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("ows", "http://www.opengis.net/ows/1.1");
namespaces.put("wmts", "http://www.opengis.net/wmts/1.0");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
XpathEngine xpath = XMLUnit.newXpathEngine();
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer)", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer'])", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:Style/ows:Identifier)", doc));
assertEquals("", xpath.evaluate("//wmts:Contents/wmts:Layer/wmts:Style/ows:Identifier", doc));
}
public void testGetCapEmptyStyleFilter() throws Exception {
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld,null , mock(RuntimeStats.class));
@SuppressWarnings("unchecked")
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{"WMTS"});
kvp.put("version", new String[]{"1.0.0"});
kvp.put("request", new String[]{"GetCapabilities"});
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
{
List<String> gridSetNames = Arrays.asList("GlobalCRS84Pixel", "GlobalCRS84Scale","EPSG:4326");
ParameterFilter styleFilter = mock(ParameterFilter.class);
when(styleFilter.getKey()).thenReturn("STYLES");
when(styleFilter.getDefaultValue()).thenReturn("Foo");
when(styleFilter.getLegalValues()).thenReturn(Collections.<String>emptyList());
TileLayer tileLayer = mockTileLayer("mockLayer", gridSetNames, Collections.singletonList(styleFilter));
when(tld.getLayerList()).thenReturn(Arrays.asList(tileLayer));
}
Conveyor conv = service.getConveyor(req, resp);
assertNotNull(conv);
final String layerName = conv.getLayerId();
assertNull(layerName);
assertEquals(Conveyor.RequestHandler.SERVICE,conv.reqHandler);
WMTSGetCapabilities wmsCap = new WMTSGetCapabilities(tld,gridsetBroker, conv.servletReq,"http://localhost:8080", "/service/wms", new NullURLMangler());
wmsCap.writeResponse(conv.servletResp,mock(RuntimeStats.class));
assertTrue(resp.containsHeader("content-disposition"));
assertEquals("inline;filename=wmts-getcapabilities.xml", resp.getHeader("content-disposition"));
// System.out.println(resp.getContentAsString());
String result = resp.getContentAsString();
Validator validator = new Validator(result);
validator.useXMLSchema(true);
validator.assertIsValid();
Document doc = XMLUnit.buildTestDocument(result);
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("ows", "http://www.opengis.net/ows/1.1");
namespaces.put("wmts", "http://www.opengis.net/wmts/1.0");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
XpathEngine xpath = XMLUnit.newXpathEngine();
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer)", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer'])", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer/wmts:Style/ows:Identifier)", doc));
assertEquals("", xpath.evaluate("//wmts:Contents/wmts:Layer/wmts:Style/ows:Identifier", doc));
}
public void testGetCapMultipleStyles() throws Exception {
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld,null , mock(RuntimeStats.class));
@SuppressWarnings("unchecked")
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{"WMTS"});
kvp.put("version", new String[]{"1.0.0"});
kvp.put("request", new String[]{"GetCapabilities"});
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
{
List<String> gridSetNames = Arrays.asList("GlobalCRS84Pixel", "GlobalCRS84Scale","EPSG:4326");
ParameterFilter styleFilter = mock(ParameterFilter.class);
when(styleFilter.getKey()).thenReturn("STYLES");
when(styleFilter.getDefaultValue()).thenReturn("Foo");
when(styleFilter.getLegalValues()).thenReturn(Arrays.asList("Foo", "Bar", "Baz"));
TileLayer tileLayer = mockTileLayer("mockLayer", gridSetNames, Collections.singletonList(styleFilter));
when(tld.getLayerList()).thenReturn(Arrays.asList(tileLayer));
}
Conveyor conv = service.getConveyor(req, resp);
assertNotNull(conv);
final String layerName = conv.getLayerId();
assertNull(layerName);
assertEquals(Conveyor.RequestHandler.SERVICE,conv.reqHandler);
WMTSGetCapabilities wmsCap = new WMTSGetCapabilities(tld,gridsetBroker, conv.servletReq,"http://localhost:8080", "/service/wms", new NullURLMangler());
wmsCap.writeResponse(conv.servletResp,mock(RuntimeStats.class));
assertTrue(resp.containsHeader("content-disposition"));
assertEquals("inline;filename=wmts-getcapabilities.xml", resp.getHeader("content-disposition"));
// System.out.println(resp.getContentAsString());
String result = resp.getContentAsString();
//Validator validator = new Validator(result);
//validator.useXMLSchema(true);
//validator.assertIsValid();
Document doc = XMLUnit.buildTestDocument(result);
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("ows", "http://www.opengis.net/ows/1.1");
namespaces.put("wmts", "http://www.opengis.net/wmts/1.0");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
XpathEngine xpath = XMLUnit.newXpathEngine();
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer)", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer'])", doc));
// There should be three styles
assertEquals("3", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer']/wmts:Style/ows:Identifier)", doc));
// Exactly one should be marked default
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer']/wmts:Style[@isDefault='true']/ows:Identifier)", doc));
// That one should be 'Foo'
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer']/wmts:Style[@isDefault='true']/ows:Identifier[text()='Foo'])", doc));
// Each of Bar and Baz should also occur
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer']/wmts:Style/ows:Identifier[text()='Bar'])", doc));
assertEquals("1", xpath.evaluate("count(//wmts:Contents/wmts:Layer[ows:Identifier='mockLayer']/wmts:Style/ows:Identifier[text()='Baz'])", doc));
}
@SuppressWarnings("unchecked")
public void testGetTileWithStyle() throws Exception {
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld,null , mock(RuntimeStats.class));
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{ "WMTS"});
kvp.put("version", new String[]{ "1.0.0"});
kvp.put("request", new String[]{ "GetTile"});
kvp.put("layer", new String[]{ "mockLayer"});
kvp.put("format", new String[]{ "image/png"});
kvp.put("TileMatrixSet", new String[]{ "GlobalCRS84Pixel"});
kvp.put("TileMatrix", new String[]{ "GlobalCRS84Pixel:1"});
kvp.put("TileRow", new String[]{ "0"});
kvp.put("TileCol", new String[]{ "0"});
kvp.put("Style", new String[]{ "Bar"}); // Note singular as required by WMTS
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
//when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
{
List<String> gridSetNames = Arrays.asList("GlobalCRS84Pixel", "GlobalCRS84Scale","EPSG:4326");
ParameterFilter styleFilter = mock(ParameterFilter.class);
when(styleFilter.getKey()).thenReturn("STYLES");
when(styleFilter.getDefaultValue()).thenReturn("Foo");
when(styleFilter.getLegalValues()).thenReturn(Arrays.asList("Foo", "Bar", "Baz"));
TileLayer tileLayer = mockTileLayer("mockLayer", gridSetNames, Collections.singletonList(styleFilter));
// Style parameter should have been made plural by the time getModifiableParameters is called.
Map<String, String> map = new HashMap<>();
map.put("STYLES", "Bar");
when(tileLayer.getModifiableParameters(
(Map)argThat(
hasEntry(
equalToIgnoringCase("styles"),
arrayContaining(equalToIgnoringCase("Bar")))),
(String)any()))
.thenReturn(Collections.unmodifiableMap(map));
when(tld.getLayerList()).thenReturn(Arrays.asList(tileLayer));
}
Conveyor conv = service.getConveyor(req, resp);
assertNotNull(conv);
final String layerName = conv.getLayerId();
assertEquals("mockLayer", layerName);
assertThat(conv, instanceOf(ConveyorTile.class));
ConveyorTile tile = (ConveyorTile) conv;
Map<String,String> parameters = tile.getParameters();
assertThat(parameters, hasEntry("STYLES", "Bar")); // Changed to plural, as used by WMS.
}
public void testDispatchCustomOperations() throws Exception {
// instantiating all the necessary machinery to perform the request
GeoWebCacheDispatcher gwcd = mock(GeoWebCacheDispatcher.class);
when(gwcd.getServletPrefix()).thenReturn(null);
service = new WMTSService(sb, tld, null, mock(RuntimeStats.class));
@SuppressWarnings("unchecked")
Map<String, String[]> kvp = new CaseInsensitiveMap();
kvp.put("service", new String[]{"WMTS"});
kvp.put("version", new String[]{"1.0.0"});
kvp.put("request", new String[]{"CustomOperation"});
HttpServletRequest req = mock(HttpServletRequest.class);
MockHttpServletResponse resp = new MockHttpServletResponse();
when(req.getCharacterEncoding()).thenReturn("UTF-8");
when(req.getParameterMap()).thenReturn(kvp);
// setup a wmts extension
service.addExtension(new WMTSExtensionImpl() {
@Override
public Conveyor getConveyor(HttpServletRequest request, HttpServletResponse response,
StorageBroker storageBroker) throws GeoWebCacheException, OWSException {
if ((request.getParameterMap().get("request")[0]).equalsIgnoreCase("CustomOperation")) {
Conveyor conveyor = new ConveyorTile(sb, null, req, resp);
conveyor.setHint("CustomOperation");
return conveyor;
}
return null;
}
@Override
public boolean handleRequest(Conveyor conveyor) throws OWSException {
if (conveyor.getHint().equalsIgnoreCase("CustomOperation")) {
try {
OutputStream os = conveyor.servletResp.getOutputStream();
os.write("CustomOperation Result".getBytes());
os.flush();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
return true;
}
return false;
}
});
// invoke the custom operation
Conveyor conveyor = service.getConveyor(req, resp);
assertThat(conveyor, notNullValue());
service.handleRequest(conveyor);
assertThat(resp.getContentAsString(), is("CustomOperation Result"));
}
}