/* (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.gwc;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertThat;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathNotExists;
import static org.hamcrest.Matchers.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.geoserver.catalog.Catalog;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.gwc.layer.GeoServerTileLayer;
import org.geoserver.gwc.layer.GeoServerTileLayerInfo;
import org.geoserver.gwc.layer.StyleParameterFilter;
import org.geoserver.test.GeoServerSystemTestSupport;
import org.geowebcache.filter.parameters.FloatParameterFilter;
import org.geowebcache.filter.parameters.ParameterFilter;
import org.geowebcache.filter.parameters.StringParameterFilter;
import org.geowebcache.util.ServletUtils;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.w3c.dom.Document;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* Integration test for GeoServer cached layers using the GWC REST API
*
*/
public class RESTIntegrationTest extends GeoServerSystemTestSupport {
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
GWC.get().getConfig().setDirectWMSIntegrationEnabled(false);
}
@Test
public void testGetLayersList() throws Exception {
final String url = "gwc/rest/layers.xml";
MockHttpServletResponse sr = getAsServletResponse(url);
assertEquals(200, sr.getStatus());
assertTrue(sr.getContentType(), sr.getContentType().startsWith("text/xml"));
Document dom = getAsDOM(url);
// print(dom);
ArrayList<String> tileLayerNames = Lists.newArrayList(GWC.get().getTileLayerNames());
Collections.sort(tileLayerNames);
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(ImmutableMap.of("atom",
"http://www.w3.org/2005/Atom")));
for (String name : tileLayerNames) {
String xpath = "//layers/layer/name[text() = '" + name + "']";
assertXpathExists(xpath, dom);
xpath = "//layers/layer/atom:link[@href = 'http://localhost:8080/geoserver/gwc/rest/layers/"
+ ServletUtils.URLEncode(name) + ".xml']";
assertXpathExists(xpath, dom);
}
}
@Test
public void testGetLayer() throws Exception {
final String layerName = getLayerId(MockData.BASIC_POLYGONS);
final String url = "gwc/rest/layers/" + layerName + ".xml";
final String id = getCatalog().getLayerByName(layerName).getId();
MockHttpServletResponse sr = getAsServletResponse(url);
assertEquals(200, sr.getStatus());
assertTrue(sr.getContentType(), sr.getContentType().startsWith("text/xml"));
Document dom = getAsDOM(url);
print(dom);
assertXpathExists("/GeoServerLayer", dom);
assertXpathEvaluatesTo(id, "/GeoServerLayer/id", dom);
assertXpathEvaluatesTo(layerName, "/GeoServerLayer/name", dom);
assertXpathEvaluatesTo("true", "/GeoServerLayer/enabled", dom);
assertXpathEvaluatesTo("image/png", "/GeoServerLayer/mimeFormats/string[1]", dom);
assertXpathEvaluatesTo("image/jpeg", "/GeoServerLayer/mimeFormats/string[2]", dom);
assertXpathEvaluatesTo("EPSG:900913",
"/GeoServerLayer/gridSubsets/gridSubset[1]/gridSetName", dom);
assertXpathNotExists("/GeoServerLayer/autoCacheStyles", dom);
}
/**
* PUT creates a new layer, shall fail if the layer id is provided and not found in the catalog
*/
@Test
public void testPutBadId() throws Exception {
final String layerName = getLayerId(MockData.BASIC_POLYGONS);
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = putLayer(url, "badId", layerName);
assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
// See GWCGeoServerRESTConfigurationProvider$RESTConverterHelper.unmarshal
String expected = "No GeoServer Layer or LayerGroup exists with id 'badId'";
assertEquals(expected, response.getContentAsString());
assertTrue(response.getContentType().startsWith("text/plain"));
}
/**
* PUT creates a new layer, shall fail if the layer id is not provided, the layer name is, but
* no such layer is found in the {@link Catalog}
*/
@Test
public void testPutNoIdBadLayerName() throws Exception {
final String url = "gwc/rest/layers/badLayerName.xml";
MockHttpServletResponse response = putLayer(url, "", "badLayerName");
assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus());
// See GWCGeoServerRESTConfigurationProvider$RESTConverterHelper.unmarshal
String expected = "GeoServer Layer or LayerGroup 'badLayerName' not found";
assertEquals(expected, response.getContentAsString());
}
@Test
public void testPutGoodIdBadLayerName() throws Exception {
final String layerName = getLayerId(MockData.BASIC_POLYGONS);
final String id = getCatalog().getLayerByName(layerName).getId();
final String url = "gwc/rest/layers/badLayerName.xml";
MockHttpServletResponse response = putLayer(url, id, "badLayerName");
assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
// See GWCGeoServerRESTConfigurationProvider$RESTConverterHelper.unmarshal
String expected = "Layer with id '" + id
+ "' found but name does not match: 'badLayerName'/'" + layerName + "'";
assertEquals(expected, response.getContentAsString());
}
/**
* Id is optional, layer name mandatory
*/
@Test
public void testPutGoodIdNoLayerName() throws Exception {
final String layerName = getLayerId(MockData.BASIC_POLYGONS);
final String id = getCatalog().getLayerByName(layerName).getId();
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = putLayer(url, id, "");
assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
// See GWCGeoServerRESTConfigurationProvider$RESTConverterHelper.unmarshal
String expected = "Layer name not provided";
assertEquals(expected, response.getContentAsString());
}
@Test
public void testPutOverExistingTileLayerFails() throws Exception {
final String layerName = getLayerId(MockData.BASIC_POLYGONS);
final String id = getCatalog().getLayerByName(layerName).getId();
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = putLayer(url, id, layerName);
assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
// See GWC's TileLayerRestlet
String expected = "Layer with name " + layerName
+ " already exists, use POST if you want to replace it.";
assertEquals(expected, response.getContentAsString());
}
@Test
public void testPutBadLayerEndpoint() throws Exception {
final String layerName = getLayerId(MockData.BASIC_POLYGONS);
final String id = getCatalog().getLayerByName(layerName).getId();
final String url = "gwc/rest/layers/badEndpoint.xml";
MockHttpServletResponse response = putLayer(url, id, layerName);
assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
// See GWC's TileLayerRestlet
String expected = "There is a mismatch between the name of the layer in the submission and the URL you specified.";
assertEquals(expected, response.getContentAsString());
}
@Test
public void testPutSuccess() throws Exception {
final String layerName = getLayerId(MockData.FORESTS);
final String id = getCatalog().getLayerByName(layerName).getId();
final GWC mediator = GWC.get();
assertTrue(mediator.tileLayerExists(layerName));
mediator.removeTileLayers(Lists.newArrayList(layerName));
assertFalse(mediator.tileLayerExists(layerName));
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = putLayer(url, id, layerName);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertTrue(mediator.tileLayerExists(layerName));
}
@Test
public void testPutParameterFilters() throws Exception {
final String layerName = getLayerId(MockData.LAKES);
final GWC mediator = GWC.get();
assertTrue(mediator.tileLayerExists(layerName));
mediator.removeTileLayers(Lists.newArrayList(layerName));
assertFalse(mediator.tileLayerExists(layerName));
final String xml = "<GeoServerLayer>"//
+ " <enabled>true</enabled>"//
+ " <name>" + layerName + "</name>"//
+ " <mimeFormats><string>image/png8</string></mimeFormats>"//
+ " <gridSubsets>"//
+ " <gridSubset><gridSetName>GoogleCRS84Quad</gridSetName></gridSubset>"//
+ " <gridSubset><gridSetName>EPSG:4326</gridSetName></gridSubset>"//
+ " </gridSubsets>"//
+ " <metaWidthHeight><int>9</int><int>6</int></metaWidthHeight>"//
+ " <parameterFilters>"//
+ " <stringParameterFilter>"//
+ " <key>BGCOLOR</key>"//
+ " <defaultValue>0xFFFFFF</defaultValue>"//
+ " <values><string>0x000000</string><string>0x888888</string></values>"//
+ " </stringParameterFilter>"//
+ " <styleParameterFilter>"//
+ " <key>STYLES</key>"//
+ " <defaultValue>capital</defaultValue>"//
+ " <allowedStyles><string>point</string><string>burg</string></allowedStyles>"//
+ " </styleParameterFilter>"//
+ " <floatParameterFilter>"//
+ " <key>ELEVATION</key>"//
+ " <defaultValue>10.1</defaultValue>"//
+ " <values>"//
+ " <float>10.1</float><float>10.2</float><float>10.3</float>"//
+ " </values>"//
+ " <threshold>1.0E-2</threshold>"//
+ " </floatParameterFilter>"//
+ " </parameterFilters>"//
+ " <gutter>20</gutter>"//
+ "</GeoServerLayer>";
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = super.putAsServletResponse(url, xml, "text/xml");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertTrue(mediator.tileLayerExists(layerName));
GeoServerTileLayer tileLayer = (GeoServerTileLayer) mediator.getTileLayerByName(layerName);
GeoServerTileLayerInfo info = tileLayer.getInfo();
assertEquals(20, info.getGutter());
assertEquals(2, tileLayer.getGridSubsets().size());
assertTrue(tileLayer.getGridSubsets().contains("GoogleCRS84Quad"));
assertTrue(tileLayer.getGridSubsets().contains("EPSG:4326"));
assertEquals(ImmutableSet.of("image/png8"), info.getMimeFormats());
assertEquals(9, info.getMetaTilingX());
assertEquals(6, info.getMetaTilingY());
List<ParameterFilter> filters = Lists.newArrayList(info.getParameterFilters());
assertEquals(3, filters.size()); // Float, String, and a Style filter that should replace
// the old String style filter.
FloatParameterFilter floatFilter=null;
StringParameterFilter stringFilter=null;
StyleParameterFilter styleFilter=null;
for(ParameterFilter filter: filters) {
if(filter instanceof FloatParameterFilter) floatFilter = (FloatParameterFilter) filter;
if(filter instanceof StringParameterFilter) stringFilter = (StringParameterFilter) filter;
if(filter instanceof StyleParameterFilter) styleFilter = (StyleParameterFilter) filter;
}
assertNotNull(floatFilter);
assertNotNull(stringFilter);
assertNotNull(styleFilter);
assertEquals("ELEVATION", floatFilter.getKey());
assertEquals("10.1", floatFilter.getDefaultValue());
assertEquals(1.0E-2f, floatFilter.getThreshold());
assertEquals(ImmutableList.of(new Float(10.1f), new Float(10.2f), new Float(10.3f)),
floatFilter.getValues());
assertEquals("BGCOLOR", stringFilter.getKey());
assertEquals("0xFFFFFF", stringFilter.getDefaultValue());
assertEquals(ImmutableList.of("0x000000", "0x888888"), stringFilter.getLegalValues());
assertEquals("STYLES", styleFilter.getKey());
}
@Test
public void testPutStyleParameterFilter() throws Exception {
final String layerName = getLayerId(MockData.LAKES);
final GWC mediator = GWC.get();
assertTrue(mediator.tileLayerExists(layerName));
mediator.removeTileLayers(Lists.newArrayList(layerName));
assertFalse(mediator.tileLayerExists(layerName));
final String xml = "<GeoServerLayer>"//
+ " <enabled>true</enabled>"//
+ " <name>" + layerName + "</name>"//
+ " <mimeFormats><string>image/png8</string></mimeFormats>"//
+ " <gridSubsets>"//
+ " <gridSubset><gridSetName>GoogleCRS84Quad</gridSetName></gridSubset>"//
+ " <gridSubset><gridSetName>EPSG:4326</gridSetName></gridSubset>"//
+ " </gridSubsets>"//
+ " <metaWidthHeight><int>9</int><int>6</int></metaWidthHeight>"//
+ " <parameterFilters>"//
+ " <styleParameterFilter>"//
+ " <key>STYLES</key>"//
+ " <defaultValue>capitals</defaultValue>"//
+ " <allowedStyles><string>points</string><string>bergs</string></allowedStyles>"//
+ " </styleParameterFilter>"//
+ " </parameterFilters>"//
+ " <gutter>20</gutter>"//
+ "</GeoServerLayer>";
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = super.putAsServletResponse(url, xml, "text/xml");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertTrue(mediator.tileLayerExists(layerName));
GeoServerTileLayer tileLayer = (GeoServerTileLayer) mediator.getTileLayerByName(layerName);
GeoServerTileLayerInfo info = tileLayer.getInfo();
assertEquals(20, info.getGutter());
assertEquals(2, tileLayer.getGridSubsets().size());
assertTrue(tileLayer.getGridSubsets().contains("GoogleCRS84Quad"));
assertTrue(tileLayer.getGridSubsets().contains("EPSG:4326"));
assertEquals(ImmutableSet.of("image/png8"), info.getMimeFormats());
assertEquals(9, info.getMetaTilingX());
assertEquals(6, info.getMetaTilingY());
List<ParameterFilter> filters = Lists.newArrayList(info.getParameterFilters());
assertEquals(1, filters.size());
StyleParameterFilter styleFilter=(StyleParameterFilter) filters.get(0);
assertEquals("STYLES", styleFilter.getKey());
assertEquals("capitals", styleFilter.getDefaultValue());
assertEquals(ImmutableSet.of("points", "bergs"), styleFilter.getStyles());
}
private MockHttpServletResponse putLayer(String url, String id, String name) throws Exception {
String xml = "<GeoServerLayer>"//
+ " <id>" + id + "</id>"//
+ " <enabled>true</enabled>"//
+ " <name>" + name + "</name>"//
+ " <mimeFormats>"//
+ " <string>image/jpeg</string>"//
+ " </mimeFormats>"//
+ " <gridSubsets>"//
+ " <gridSubset>"//
+ " <gridSetName>EPSG:900913</gridSetName>"//
+ " </gridSubset>"//
+ " </gridSubsets>"//
+ " <metaWidthHeight>"//
+ " <int>4</int>"//
+ " <int>4</int>"//
+ " </metaWidthHeight>"//
+ " <autoCacheStyles>true</autoCacheStyles>"//
+ "</GeoServerLayer>";
final String contentType = "text/xml";
MockHttpServletResponse response = super.putAsServletResponse(url, xml, contentType);
return response;
}
@Test
public void testDelete() throws Exception {
final String layerName = getLayerId(MockData.BRIDGES);
final GWC mediator = GWC.get();
assertTrue(mediator.tileLayerExists(layerName));
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = super.deleteAsServletResponse(url);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertFalse(mediator.tileLayerExists(layerName));
}
@Test
public void testDeleteNonExistentLayer() throws Exception {
final String url = "gwc/rest/layers/badLayerName.xml";
MockHttpServletResponse response = super.deleteAsServletResponse(url);
assertEquals(HttpServletResponse.SC_NOT_FOUND, response.getStatus());
// See GWC's TileLayerRestlet
assertEquals("Unknown layer: badLayerName", response.getContentAsString());
}
@Test
public void testPost() throws Exception {
final String layerName = getLayerId(MockData.ROAD_SEGMENTS);
final GWC mediator = GWC.get();
assertTrue(mediator.tileLayerExists(layerName));
final String xml = "<GeoServerLayer>"//
+ " <enabled>true</enabled>"//
+ " <name>" + layerName + "</name>"//
+ " <mimeFormats><string>image/png8</string></mimeFormats>"//
+ " <gridSubsets>"//
+ " <gridSubset><gridSetName>GoogleCRS84Quad</gridSetName></gridSubset>"//
+ " <gridSubset><gridSetName>EPSG:4326</gridSetName></gridSubset>"//
+ " </gridSubsets>"//
+ " <metaWidthHeight><int>9</int><int>6</int></metaWidthHeight>"//
+ " <parameterFilters>"//
+ " <styleParameterFilter>"//
+ " <key>STYLES</key>"//
+ " <defaultValue>capitals</defaultValue>"//
+ " <allowedStyles><string>burg</string><string>point</string></allowedStyles>"//
+ " </styleParameterFilter>"//
+ " <floatParameterFilter>"//
+ " <key>ELEVATION</key>"//
+ " <defaultValue>10.1</defaultValue>"//
+ " <values>"//
+ " <float>10.1</float><float>10.2</float><float>10.3</float>"//
+ " </values>"//
+ " <threshold>1.0E-2</threshold>"//
+ " </floatParameterFilter>"//
+ " </parameterFilters>"//
+ " <gutter>20</gutter>"//
+ "</GeoServerLayer>";
final String url = "gwc/rest/layers/" + layerName + ".xml";
MockHttpServletResponse response = super.postAsServletResponse(url, xml, "text/xml");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertTrue(mediator.tileLayerExists(layerName));
GeoServerTileLayer tileLayer = (GeoServerTileLayer) mediator.getTileLayerByName(layerName);
GeoServerTileLayerInfo info = tileLayer.getInfo();
assertEquals(20, info.getGutter());
assertEquals(2, tileLayer.getGridSubsets().size());
assertTrue(tileLayer.getGridSubsets().contains("GoogleCRS84Quad"));
assertTrue(tileLayer.getGridSubsets().contains("EPSG:4326"));
assertEquals(ImmutableSet.of("image/png8"), info.getMimeFormats());
assertEquals(9, info.getMetaTilingX());
assertEquals(6, info.getMetaTilingY());
List<ParameterFilter> filters = Lists.newArrayList(info.getParameterFilters());
assertEquals(2, filters.size());
FloatParameterFilter floatFilter=null;
StyleParameterFilter styleFilter=null;
for(ParameterFilter filter: filters) {
if(filter instanceof FloatParameterFilter) floatFilter = (FloatParameterFilter) filter;
if(filter instanceof StyleParameterFilter) styleFilter = (StyleParameterFilter) filter;
}
assertNotNull(floatFilter);
assertNotNull(styleFilter);
assertEquals("ELEVATION", floatFilter.getKey());
assertEquals("10.1", floatFilter.getDefaultValue());
assertEquals(1.0E-2f, floatFilter.getThreshold());
assertEquals(ImmutableList.of(new Float(10.1f), new Float(10.2f), new Float(10.3f)),
floatFilter.getValues());
assertEquals("STYLES", styleFilter.getKey());
assertEquals("capitals", styleFilter.getDefaultValue());
assertEquals(ImmutableSet.of("burg", "point"), styleFilter.getStyles());
}
@Test
public void testPostLegacyAutoStyles() throws Exception {
final String layerName = getLayerId(MockData.ROAD_SEGMENTS);
final GWC mediator = GWC.get();
assertTrue(mediator.tileLayerExists(layerName));
final String url = "gwc/rest/layers/" + layerName + ".xml";
{
final String xml = "<GeoServerLayer>"//
+ " <name>" + layerName + "</name>"//
+ " <autoCacheStyles>true</autoCacheStyles>"
+ "</GeoServerLayer>";
MockHttpServletResponse response = super.postAsServletResponse(url, xml, "text/xml");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
GeoServerTileLayer tileLayer = (GeoServerTileLayer) mediator.getTileLayerByName(layerName);
GeoServerTileLayerInfo info = tileLayer.getInfo();
List<ParameterFilter> filters = Lists.newArrayList(info.getParameterFilters());
assertThat(
filters,
contains(allOf(
Matchers.<ParameterFilter>hasProperty("key", is("STYLES")),
isA((Class<ParameterFilter>)StyleParameterFilter.class.asSubclass(ParameterFilter.class))))
);
}
{
final String xml = "<GeoServerLayer>"//
+ " <name>" + layerName + "</name>"//
+ " <autoCacheStyles>false</autoCacheStyles>"
+ "</GeoServerLayer>";
MockHttpServletResponse response = super.postAsServletResponse(url, xml, "text/xml");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
GeoServerTileLayer tileLayer = (GeoServerTileLayer) mediator.getTileLayerByName(layerName);
GeoServerTileLayerInfo info = tileLayer.getInfo();
List<ParameterFilter> filters = Lists.newArrayList(info.getParameterFilters());
assertThat(
filters,
not(contains(allOf(
Matchers.<ParameterFilter>hasProperty("key", is("STYLES")),
isA((Class<ParameterFilter>)StyleParameterFilter.class.asSubclass(ParameterFilter.class))))
));
}
}
}