/* (c) 2014 - 2015 Open Source Geospatial Foundation - all rights reserved
* (c) 2014 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.capabilities;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import org.custommonkey.xmlunit.SimpleNamespaceContext;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XpathEngine;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.config.GeoServerInfo;
import org.geoserver.config.impl.ContactInfoImpl;
import org.geoserver.config.impl.GeoServerImpl;
import org.geoserver.config.impl.GeoServerInfoImpl;
import org.geoserver.data.test.MockData;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.data.test.SystemTestData.LayerProperty;
import org.geoserver.ows.LocalWorkspace;
import org.geoserver.ows.util.KvpUtils;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geoserver.platform.resource.Paths;
import org.geoserver.platform.resource.Resource;
import org.geoserver.wms.GetCapabilitiesRequest;
import org.geoserver.wms.WMS;
import org.geoserver.wms.WMSInfo;
import org.geoserver.wms.WMSInfoImpl;
import org.geoserver.wms.WMSTestSupport;
import org.geoserver.wms.wms_1_1_1.GetFeatureInfoTest;
import org.geotools.xml.transform.TransformerBase;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Base class for legendURL support in GetCapabilities tests.
*
* @author Mauro Bartolomeoli (mauro.bartolomeoli at geo-solutions.it)
*
*/
public abstract class GetCapabilitiesLegendURLTest extends WMSTestSupport {
/** default base url to feed a GetCapabilitiesTransformer with for it to append the DTD location */
protected static final String baseUrl = "http://localhost/geoserver";
/** test map formats to feed a GetCapabilitiesTransformer with */
protected static final Set<String> mapFormats = Collections.singleton("image/png");
/** test legend formats to feed a GetCapabilitiesTransformer with */
protected static final Set<String> legendFormats = Collections.singleton("image/png");
/**
* a mocked up {@link GeoServer} config, almost empty after setUp(), except for the
* {@link WMSInfo}, {@link GeoServerInfo} and empty {@link Catalog}, Specific tests should add
* content as needed
*/
protected GeoServerImpl geosConfig;
/**
* a mocked up {@link GeoServerInfo} for {@link #geosConfig}. Specific tests should set its
* properties as needed
*/
protected GeoServerInfoImpl geosInfo;
/**
* a mocked up {@link WMSInfo} for {@link #geosConfig}, empty except for the WMSInfo after
* setUp(), Specific tests should set its properties as needed
*/
protected WMSInfoImpl wmsInfo;
/**
* a mocked up {@link Catalog} for {@link #geosConfig}, empty after setUp(), Specific tests
* should add content as needed
*/
protected Catalog catalog;
protected GetCapabilitiesRequest req;
protected WMS wmsConfig;
protected XpathEngine XPATH;
/** Test layers */
public static QName SQUARES = new QName(MockData.CITE_URI, "squares", MockData.CITE_PREFIX);
public static QName STATES = new QName(MockData.CITE_URI, "states", MockData.CITE_PREFIX);
public static QName WORLD = new QName("http://www.geo-solutions.it", "world", "gs");
/**
* Adds required styles to test the selection of maximum and minimum denominator from style's rules.
*/
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
super.onSetUp(testData);
this.catalog = getCatalog();
File dataDirRoot = testData.getDataDirectoryRoot();
// create legendsamples folder
new File(dataDirRoot.getAbsolutePath() + File.separator
+ LegendSampleImpl.LEGEND_SAMPLES_FOLDER).mkdir();
testData.addStyle("squares","squares.sld",GetFeatureInfoTest.class,catalog);
testData.addVectorLayer(SQUARES,Collections.EMPTY_MAP,"squares.properties",
GetCapabilitiesLegendURLTest.class,catalog);
WorkspaceInfo workspaceInfo = catalog.getWorkspaceByName(MockData.CITE_PREFIX);
testData.addStyle(workspaceInfo, "states","Population.sld",GetCapabilitiesLegendURLTest.class,catalog);
Map<LayerProperty, Object> properties = new HashMap<LayerProperty, Object>();
properties.put(LayerProperty.STYLE, "states");
LocalWorkspace.set(workspaceInfo);
testData.addVectorLayer(STATES,properties,"states.properties",
GetCapabilitiesLegendURLTest.class,catalog);
LocalWorkspace.set(null);
testData.addStyle("temperature", "temperature.sld", WMSTestSupport.class, catalog);
properties = new HashMap<LayerProperty, Object>();
properties.put(LayerProperty.STYLE, "temperature");
testData.addRasterLayer(WORLD, "world.tiff", null, properties, SystemTestData.class, catalog);
}
@Before
public void internalSetUp() throws IOException {
this.catalog = getCatalog();
geosConfig = new GeoServerImpl();
geosInfo = new GeoServerInfoImpl(geosConfig);
geosInfo.setContact(new ContactInfoImpl());
geosConfig.setGlobal(geosInfo);
wmsInfo = new WMSInfoImpl();
geosConfig.add(wmsInfo);
geosConfig.setCatalog(catalog);
wmsConfig = new WMS(geosConfig);
wmsConfig.setApplicationContext(applicationContext);
req = new GetCapabilitiesRequest();
req.setBaseUrl(baseUrl);
getTestData().copyTo(
getClass().getResourceAsStream("/legendURL/BasicPolygons.png"),
LegendSampleImpl.LEGEND_SAMPLES_FOLDER + "/BasicPolygons.png");
getTestData().copyTo(getClass().getResourceAsStream("/legendURL/Bridges.png"),
LegendSampleImpl.LEGEND_SAMPLES_FOLDER + "/Bridges.png");
Map<String, String> namespaces = new HashMap<String, String>();
namespaces.put("xlink", "http://www.w3.org/1999/xlink");
namespaces.put("wms", "http://www.opengis.net/wms");
namespaces.put("ows", "http://www.opengis.net/ows");
XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces));
XPATH = XMLUnit.newXpathEngine();
}
/**
* Accessor for global catalog instance from the test application context.
*/
protected Catalog getCatalog() {
return (Catalog) applicationContext.getBean("catalog");
}
/**
* Tests that already cached icons are read from disk and
* used to calculate size.
*/
@Test
public void testCachedLegendURLSize() throws Exception {
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
NodeList legendURLs = XPATH.getMatchingNodes(
getLegendURLXPath("cite:BasicPolygons"), dom);
assertEquals(1, legendURLs.getLength());
Element legendURL = (Element) legendURLs.item(0);
assertTrue(legendURL.hasAttribute("width"));
assertEquals("50", legendURL.getAttribute("width"));
assertTrue(legendURL.hasAttribute("height"));
assertEquals("10", legendURL.getAttribute("height"));
}
/**
* Tests that folder for legend samples is created, if missing.
*/
@Test
public void testCachedLegendURLFolderCreated() throws Exception {
GeoServerResourceLoader loader = GeoServerExtensions.bean(GeoServerResourceLoader.class);
File samplesFolder = new File(loader.getBaseDirectory().getAbsolutePath() + File.separator
+ LegendSampleImpl.LEGEND_SAMPLES_FOLDER);
removeFileOrFolder(samplesFolder);
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
assertTrue(samplesFolder.exists());
}
/**
* Tests the layer names are workspace qualified
*
*/
@Test
public void testLayerWorkspaceQualified() throws Exception {
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
// print(dom);
String legendURL = XPATH.evaluate(getLegendURLXPath("cite:squares") + "/"
+ getElementPrefix() + "OnlineResource/@xlink:href", dom);
Map<String, Object> kvp = KvpUtils.parseQueryString(legendURL);
assertEquals("cite:squares", kvp.get("layer"));
}
/**
* Tests that not existing icons are created on disk and
* used to calculate size.
*/
@Test
public void testCreatedLegendURLSize() throws Exception {
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
NodeList legendURLs = XPATH.getMatchingNodes(
getLegendURLXPath("cite:squares"), dom);
assertEquals(1, legendURLs.getLength());
Element legendURL = (Element) legendURLs.item(0);
assertTrue(legendURL.hasAttribute("width"));
assertFalse("20".equals(legendURL.getAttribute("width")));
assertTrue(legendURL.hasAttribute("height"));
assertFalse("20".equals(legendURL.getAttribute("height")));
File sampleFile = getSampleFile("squares");
assertTrue(sampleFile.exists());
}
@Test
public void testCreatedRasterLegendURLSize() throws Exception {
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
NodeList legendURLs = XPATH.getMatchingNodes(
getLegendURLXPath("gs:world"), dom);
assertEquals(1, legendURLs.getLength());
Element legendURL = (Element) legendURLs.item(0);
assertTrue(legendURL.hasAttribute("width"));
assertFalse("20".equals(legendURL.getAttribute("width")));
assertTrue(legendURL.hasAttribute("height"));
assertFalse("20".equals(legendURL.getAttribute("height")));
File sampleFile = getSampleFile("temperature");
assertTrue(sampleFile.exists());
}
private File getSampleFile(String sampleName) {
return new File(testData.getDataDirectoryRoot().getAbsolutePath()
+ File.separator + LegendSampleImpl.LEGEND_SAMPLES_FOLDER + File.separator
+ sampleName + ".png");
}
/**
* Tests that not existing icons for workspace bound styles are created on disk
* in the workspace styles folder.
*/
@Test
public void testCreatedLegendURLFromWorkspaceSize() throws Exception {
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
NodeList legendURLs = XPATH.getMatchingNodes(
getLegendURLXPath("cite:states"), dom);
assertEquals(1, legendURLs.getLength());
Element legendURL = (Element) legendURLs.item(0);
assertTrue(legendURL.hasAttribute("width"));
assertFalse("20".equals(legendURL.getAttribute("width")));
assertTrue(legendURL.hasAttribute("height"));
assertFalse("20".equals(legendURL.getAttribute("height")));
File sampleFile = getSampleFile("cite_states");
assertTrue(sampleFile.exists());
}
/**
* Tests that already cached icons are recreated if related
* SLD is newer.
*/
@Test
public void testCachedLegendURLUpdatedSize() throws Exception {
GeoServerResourceLoader loader = GeoServerExtensions.bean(GeoServerResourceLoader.class);
Resource sldResource = loader.get(Paths.path("styles", "Bridges.sld"));
File sampleFile = getSampleFile("Bridges");
long lastTime = sampleFile.lastModified();
long lastLength = sampleFile.length();
long previousTime = sldResource.lastmodified();
sldResource.file().setLastModified(lastTime + 1000);
// force cleaning of samples cache, to get updates on files
((LegendSampleImpl)GeoServerExtensions.bean(LegendSample.class)).reloaded();
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
NodeList legendURLs = XPATH.getMatchingNodes(
getLegendURLXPath("cite:Bridges"), dom);
assertEquals(1, legendURLs.getLength());
Element legendURL = (Element) legendURLs.item(0);
assertTrue(legendURL.hasAttribute("width"));
assertEquals("20", legendURL.getAttribute("width"));
assertTrue(legendURL.hasAttribute("height"));
assertEquals("20", legendURL.getAttribute("height"));
assertFalse(getSampleFile("Bridges").length() == lastLength);
sldResource.file().setLastModified(previousTime);
}
/**
* Tests that already cached icons are recreated if related
* SLD is newer (using Catalog events).
*/
@Test
public void testCachedLegendURLUpdatedSize2() throws Exception {
GeoServerResourceLoader loader = GeoServerExtensions.bean(GeoServerResourceLoader.class);
Resource sldResource = loader.get(Paths.path("styles", "Bridges.sld"));
File sampleFile = getSampleFile("Bridges");
long lastTime = sampleFile.lastModified();
long lastLength = sampleFile.length();
long previousTime = sldResource.lastmodified();
sldResource.file().setLastModified(lastTime + 1000);
catalog.firePostModified(catalog.getStyleByName("Bridges"), new ArrayList<String>(), new ArrayList(), new ArrayList());
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
NodeList legendURLs = XPATH.getMatchingNodes(
getLegendURLXPath("cite:Bridges"), dom);
assertEquals(1, legendURLs.getLength());
Element legendURL = (Element) legendURLs.item(0);
assertTrue(legendURL.hasAttribute("width"));
assertEquals("20", legendURL.getAttribute("width"));
assertTrue(legendURL.hasAttribute("height"));
assertEquals("20", legendURL.getAttribute("height"));
assertFalse(getSampleFile("Bridges").length() == lastLength);
sldResource.file().setLastModified(previousTime);
}
/**
* Tests that already cached icons are read from disk and
* used to calculate size.
*/
@Test
public void testOnlineResourceWidthHeight() throws Exception {
TransformerBase tr = createTransformer();
tr.setIndentation(2);
Document dom = WMSTestSupport.transform(req, tr);
NodeList onlineResources = XPATH.getMatchingNodes(
getOnlineResourceXPath("cite:BasicPolygons"), dom);
assertEquals(1, onlineResources.getLength());
Element onlineResource = (Element) onlineResources.item(0);
String href = onlineResource.getAttribute("xlink:href");
assertNotNull(href);
assertTrue(href.contains("width=20"));
assertTrue(href.contains("height=20"));
}
private String getLegendURLXPath(String layerName) {
return "/"+ getElementPrefix() + getRootElement() + "/"+ getElementPrefix() + "Capability/"+ getElementPrefix() + "Layer/"+ getElementPrefix() + "Layer["+ getElementPrefix() + "Name/text()='"+layerName+"']/"+ getElementPrefix() + "Style/"+ getElementPrefix() + "LegendURL";
}
private String getOnlineResourceXPath(String layerName) {
return "/"+ getElementPrefix() + getRootElement() + "/"+ getElementPrefix() + "Capability/"+ getElementPrefix() + "Layer/"+ getElementPrefix() + "Layer["+ getElementPrefix() + "Name/text()='"+layerName+"']/"+ getElementPrefix() + "Style/"+ getElementPrefix() + "LegendURL/"+getElementPrefix()+"OnlineResource";
}
private void removeFileOrFolder(File file) {
if (!file.exists()) {
return;
}
if (!file.isDirectory()) {
file.delete();
} else {
String[] list = file.list();
for (int i = 0; i < list.length; i++) {
removeFileOrFolder(new File(file.getAbsolutePath() + File.separator + list[i]));
}
file.delete();
}
}
/**
* Each WMS version suite of tests has its own TransformerBase implementation.
*
*
*/
protected abstract TransformerBase createTransformer();
/**
* Each WMS version has a different root name for the Capabilities XML document.
*
*
*/
protected abstract String getRootElement();
/**
* Each WMS version uses a different element prefix.
*
*
*/
protected abstract String getElementPrefix();
}