/* (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.rest.catalog; import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo; import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists; import static org.custommonkey.xmlunit.XMLAssert.assertXpathNotExists; import static org.geoserver.rest.catalog.HttpTestUtils.hasHeader; import static org.geoserver.rest.catalog.HttpTestUtils.hasStatus; import static org.geoserver.rest.catalog.HttpTestUtils.istream; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.isEmptyString; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.*; import java.net.URL; import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONException; import net.sf.json.JSONObject; import org.custommonkey.xmlunit.XMLUnit; import org.custommonkey.xmlunit.XpathEngine; import org.geoserver.catalog.CatalogBuilder; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.ProjectionPolicy; import org.geoserver.catalog.ResourceInfo; import org.geoserver.catalog.TestHttpClientRule; import org.geoserver.catalog.WMSLayerInfo; import org.geoserver.catalog.WMSStoreInfo; import org.geoserver.data.test.SystemTestData; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.rest.RestBaseController; import org.geoserver.test.http.MockHttpClient; import org.geoserver.test.http.MockHttpResponse; import org.geotools.feature.NameImpl; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.CRS; import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.w3c.dom.Document; import org.hamcrest.Matchers; import junit.framework.AssertionFailedError; import org.springframework.http.HttpStatus; import org.springframework.mock.web.MockHttpServletResponse; public class WMSLayerTest extends CatalogRESTTestSupport { @Rule public TestHttpClientRule clientMocker = new TestHttpClientRule(); @Override protected void onSetUp(SystemTestData testData) throws Exception { super.onSetUp(testData); // we need to add a wms store CatalogBuilder cb = new CatalogBuilder(catalog); cb.setWorkspace(catalog.getWorkspaceByName("sf")); WMSStoreInfo wms = cb.buildWMSStore("demo"); wms.setCapabilitiesURL(clientMocker.getServer()+"/geoserver/wms?REQUEST=GetCapabilities&VERSION=1.3.0&SERVICE=WMS"); catalog.add(wms); // and a wms layer as well (cannot use the builder, would turn this test into an online one addStatesWmsLayer(); } @Before public void addStatesWmsLayer() throws Exception { String capabilities = clientMocker.getServer() + "/geoserver/wms?REQUEST=GetCapabilities&VERSION=1.3.0&SERVICE=WMS"; WMSLayerInfo wml = catalog.getResourceByName("sf", "states", WMSLayerInfo.class); if (wml == null) { wml = catalog.getFactory().createWMSLayer(); wml.setName("states"); wml.setNativeName("topp:states"); wml.setStore(catalog.getStoreByName("demo", WMSStoreInfo.class)); wml.setCatalog(catalog); wml.setNamespace(catalog.getNamespaceByPrefix("sf")); wml.setSRS("EPSG:4326"); CoordinateReferenceSystem wgs84 = CRS.decode("EPSG:4326"); wml.setNativeCRS(wgs84); wml.setLatLonBoundingBox(new ReferencedEnvelope(-110, 0, -60, 50, wgs84)); wml.setProjectionPolicy(ProjectionPolicy.FORCE_DECLARED); catalog.add(wml); } MockHttpClient client = new MockHttpClient(); client.expectGet( new URL(capabilities), new MockHttpResponse(getClass().getResource("caps130.xml"), "text/xml")); clientMocker.bind(client, capabilities); } @After public void removeLayer() throws Exception { LayerInfo l = catalog.getLayerByName(new NameImpl("sf", "states")); if(l != null) { catalog.remove(l); } } @Before public void removeBugsites() throws Exception { LayerInfo l = catalog.getLayerByName(new NameImpl("sf", "bugsites")); if(l != null) { catalog.remove(l); } ResourceInfo r = catalog.getResourceByName("sf", "bugsites", WMSLayerInfo.class); if (r != null) { catalog.remove(r); } } @Test public void testBeanPresent() throws Exception { assertThat(GeoServerExtensions.extensions(RestBaseController.class), hasItem(instanceOf(WMSLayerController.class))); } @Test public void testGetAllByWorkspace() throws Exception { MockHttpServletResponse response = getAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmslayers.xml"); assertThat(response, hasStatus(HttpStatus.OK)); Document dom = dom(istream(response)); assertEquals( catalog.getResourcesByNamespace( catalog.getNamespaceByPrefix( "sf"), WMSLayerInfo.class ).size(), dom.getElementsByTagName( "wmsLayer").getLength() ); } @Test public void testGetAllByWMSStore() throws Exception { MockHttpServletResponse response = getAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers.xml"); assertThat(response, hasStatus(HttpStatus.OK)); Document dom = dom(istream(response)); assertEquals( 1, dom.getElementsByTagName( "wmsLayer").getLength() ); assertXpathEvaluatesTo( "1", "count(//wmsLayer/name[text()='states'])", dom ); } @Test public void testGetAllAvailable() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers.xml?list=available", 200); //print(dom) // can't control the demo server enough to check the type names, but it should have something // more than just topp:states assertXpathExists("/list/wmsLayerName[text() = 'world4326']", dom); assertXpathExists("/list/wmsLayerName[text() = 'anotherLayer']", dom); assertXpathNotExists("/list/wmsLayerName[text() = 'topp:states']", dom); } @SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void testGetAllAvailableJSON() throws Exception { MockHttpServletResponse response = getAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers.json?list=available"); assertThat(response, hasStatus(HttpStatus.OK)); JSON json = json(response); JSONArray names = (JSONArray) ((JSONObject)((JSONObject)json).get("list")).get("string"); assertThat(names, (Matcher) containsInAnyOrder(equalTo("world4326"),equalTo("anotherLayer"))); } @Override protected JSON getAsJSON(String path) throws Exception { MockHttpServletResponse response = getAsServletResponse(path); try{ return json(response); } catch (JSONException ex) { throw new AssertionFailedError("Invalid JSON: \""+response.getContentAsString()+"\""); } } @Test public void testPutAllUnauthorized() throws Exception { assertEquals( 405, putAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers").getStatus() ); } @Test public void testDeleteAllUnauthorized() throws Exception { assertEquals( 405, deleteAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers").getStatus() ); } @Test public void testPostAsXML() throws Exception { assertThat(catalog.getResourceByName("sf", "bugsites", WMSLayerInfo.class), nullValue()); String xml = "<wmsLayer>"+ "<name>bugsites</name>"+ "<nativeName>world4326</nativeName>"+ "<srs>EPSG:4326</srs>" + "<nativeCRS>EPSG:4326</nativeCRS>" + "<store>demo</store>" + "</wmsLayer>"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/", xml, "text/xml"); assertThat(response, hasStatus(HttpStatus.CREATED )); assertThat(response, hasHeader("Location", Matchers.endsWith("/workspaces/sf/wmsstores/demo/wmslayers/bugsites"))); WMSLayerInfo layer = catalog.getResourceByName("sf", "bugsites", WMSLayerInfo.class); assertThat(layer, hasProperty("nativeBoundingBox", notNullValue())); } @Test public void testPostAsXMLNoWorkspace() throws Exception { assertThat(catalog.getResourceByName("sf", "bugsites", WMSLayerInfo.class), nullValue()); String xml = "<wmsLayer>"+ "<name>bugsites</name>"+ "<nativeName>world4326</nativeName>"+ "<srs>EPSG:4326</srs>" + "<nativeCRS>EPSG:4326</nativeCRS>" + "<store>demo</store>" + "</wmsLayer>"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmslayers/", xml, "text/xml"); assertThat(response, hasStatus(HttpStatus.CREATED )); assertThat(response, hasHeader("Location", Matchers.endsWith("/workspaces/sf/wmslayers/bugsites"))); WMSLayerInfo layer = catalog.getResourceByName("sf", "bugsites", WMSLayerInfo.class); assertThat(layer, hasProperty("nativeBoundingBox", notNullValue())); } @Test public void testPostAsJSON() throws Exception { assertThat(catalog.getResourceByName("sf", "bugsites", WMSLayerInfo.class), nullValue()); String json = "{" + "'wmsLayer':{" + "'name':'bugsites'," + "'nativeName':'world4326'," + "'srs':'EPSG:4326'," + "'nativeCRS':'EPSG:4326'," + "'store':'demo'" + "}" + "}"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/", json, "text/json"); assertThat(response, hasStatus(HttpStatus.CREATED )); assertThat(response, hasHeader("Location", Matchers.endsWith("/workspaces/sf/wmsstores/demo/wmslayers/bugsites"))); WMSLayerInfo layer = catalog.getResourceByName("sf", "bugsites", WMSLayerInfo.class); assertThat(layer, hasProperty("nativeBoundingBox", notNullValue())); } @Test public void testPostToResource() throws Exception { String xml = "<wmsLayer>"+ "<name>og:restricted</name>"+ "</wmsLayer>"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/states", xml, "text/xml"); assertEquals( 405, response.getStatus() ); } @Test public void testGetAsXML() throws Exception { MockHttpServletResponse response = getAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmslayers/states.xml"); assertThat(response, hasStatus(HttpStatus.OK)); Document dom = dom(istream(response)); assertEquals( "wmsLayer", dom.getDocumentElement().getNodeName() ); assertXpathEvaluatesTo("states", "/wmsLayer/name", dom); assertXpathEvaluatesTo( "EPSG:4326", "/wmsLayer/srs", dom); assertEquals( CRS.decode( "EPSG:4326" ).toWKT(), xp.evaluate( "/wmsLayer/nativeCRS", dom ) ); WMSLayerInfo wml = catalog.getResourceByName( "sf", "states", WMSLayerInfo.class ); ReferencedEnvelope re = wml.getLatLonBoundingBox(); assertXpathEvaluatesTo( re.getMinX()+"" , "/wmsLayer/latLonBoundingBox/minx", dom ); assertXpathEvaluatesTo( re.getMaxX()+"" , "/wmsLayer/latLonBoundingBox/maxx", dom ); assertXpathEvaluatesTo( re.getMinY()+"" , "/wmsLayer/latLonBoundingBox/miny", dom ); assertXpathEvaluatesTo( re.getMaxY()+"" , "/wmsLayer/latLonBoundingBox/maxy", dom ); } @Test public void testGetAsJSON() throws Exception { JSON json = getAsJSON( RestBaseController.ROOT_PATH+"/workspaces/sf/wmslayers/states.json"); JSONObject featureType = ((JSONObject)json).getJSONObject("wmsLayer"); assertNotNull(featureType); assertEquals( "states", featureType.get("name") ); assertEquals( CRS.decode("EPSG:4326").toWKT(), featureType.get( "nativeCRS") ); assertEquals( "EPSG:4326", featureType.get( "srs") ); } @Test public void testGetAsHTML() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH+"/workspaces/sf/wmslayers/states.html"); // print(dom); } @Test public void testGetWrongWMSLayer() throws Exception { // Parameters for the request String ws = "sf"; String wms = "demo"; String wl = "statessssss"; // Request path String requestPath = RestBaseController.ROOT_PATH+"/workspaces/" + ws + "/wmslayers/" + wl + ".html"; String requestPath2 = RestBaseController.ROOT_PATH+"/workspaces/" + ws + "/wmsstores/" + wms + "/wmslayers/" + wl + ".html"; // Exception path String exception = "No such cascaded wms: "+ws+","+wl; String exception2 = "No such cascaded wms layer: "+ws+","+wms+","+wl; // CASE 1: No wmsstore set // First request should thrown an exception MockHttpServletResponse response = getAsServletResponse(requestPath); assertThat(response, hasStatus(HttpStatus.NOT_FOUND)); assertThat(response.getContentAsString(), containsString( exception)); // Same request with ?quietOnNotFound should not throw an exception response = getAsServletResponse(requestPath + "?quietOnNotFound=true"); assertThat(response, hasStatus(HttpStatus.NOT_FOUND)); assertThat(response.getContentAsString(), not(containsString( exception))); // No exception thrown assertThat(response.getContentAsString(), isEmptyString()); // CASE 2: wmsstore set // First request should thrown an exception response = getAsServletResponse(requestPath2); assertThat(response, hasStatus(HttpStatus.NOT_FOUND)); assertThat(response.getContentAsString(), containsString( exception)); // Same request with ?quietOnNotFound should not throw an exception response = getAsServletResponse(requestPath2 + "?quietOnNotFound=true"); assertThat(response, hasStatus(HttpStatus.NOT_FOUND)); assertThat(response.getContentAsString(), not(containsString( exception))); // No exception thrown assertThat(response.getContentAsString(), isEmptyString()); } @Test public void testPut() throws Exception { String xml = "<wmsLayer>" + "<title>Lots of states here</title>" + "</wmsLayer>"; MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/states", xml, "text/xml"); assertThat( response, hasStatus(HttpStatus.OK) ); Document dom = getAsDOM(RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/states.xml"); assertXpathEvaluatesTo("Lots of states here", "/wmsLayer/title", dom ); WMSLayerInfo wli = catalog.getResourceByName( "sf", "states", WMSLayerInfo.class); assertEquals( "Lots of states here", wli.getTitle() ); } @Test public void testPutNonDestructive() throws Exception { WMSLayerInfo wli = catalog.getResourceByName( "sf", "states", WMSLayerInfo.class); wli.setEnabled(true); catalog.save(wli); wli = catalog.getResourceByName( "sf", "states", WMSLayerInfo.class); assertTrue(wli.isEnabled()); boolean isAdvertised = wli.isAdvertised(); String xml = "<wmsLayer>" + "<title>Lots of states here</title>" + "</wmsLayer>"; MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/states", xml, "text/xml"); assertEquals( 200, response.getStatus() ); wli = catalog.getResourceByName( "sf", "states", WMSLayerInfo.class); assertTrue(wli.isEnabled()); assertEquals(isAdvertised, wli.isAdvertised()); } @Test public void testPutNonExistant() throws Exception { String xml = "<wmsLayer>" + "<title>new title</title>" + "</wmsLayer>"; MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/bugsites", xml, "text/xml"); assertEquals( 404, response.getStatus() ); } @Test public void testDelete() throws Exception { assertNotNull(catalog.getResourceByName("sf", "states", WMSLayerInfo.class)); assertThat( deleteAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/states"), hasStatus(HttpStatus.OK)); assertNull( catalog.getResourceByName("sf", "states", WMSLayerInfo.class)); } @Test public void testDeleteNonExistant() throws Exception { assertEquals( 404, deleteAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/NonExistent").getStatus()); } void addLayer() { LayerInfo l = catalog.getLayerByName(new NameImpl("sf", "states")); if (l == null) { l = catalog.getFactory().createLayer(); l.setResource(catalog.getResourceByName("sf", "states", WMSLayerInfo.class)); catalog.add(l); } } @Test public void testDeleteNonRecursive() throws Exception { addLayer(); assertNotNull(catalog.getResourceByName("sf", "states", WMSLayerInfo.class)); assertEquals( 403, deleteAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/states").getStatus()); } @Test public void testDeleteRecursive() throws Exception { addLayer(); assertNotNull(catalog.getLayerByName("sf:states")); assertNotNull(catalog.getResourceByName("sf", "states", WMSLayerInfo.class)); assertEquals( 200, deleteAsServletResponse( RestBaseController.ROOT_PATH+"/workspaces/sf/wmsstores/demo/wmslayers/states?recurse=true").getStatus()); assertNull( catalog.getLayerByName("sf:states")); assertNull( catalog.getResourceByName("sf", "states", WMSLayerInfo.class)); } @Test public void testResourceLink() throws Exception { addLayer(); Document doc = getAsDOM( RestBaseController.ROOT_PATH+"/layers/states.xml"); XpathEngine xpath = XMLUnit.newXpathEngine(); String resourceUrl = xpath.evaluate("//resource/atom:link/@href", doc); resourceUrl = resourceUrl.substring(resourceUrl.indexOf("/rest")); doc = getAsDOM(resourceUrl); assertXpathEvaluatesTo("states", "/wmsLayer/name", doc); } }