/* (c) 2017 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.rest.catalog; import net.sf.json.JSON; import net.sf.json.JSONObject; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.custommonkey.xmlunit.XMLUnit; import org.custommonkey.xmlunit.XpathEngine; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CatalogFacade; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.PropertyStyleHandler; import org.geoserver.catalog.SLDHandler; import org.geoserver.catalog.StyleInfo; import org.geoserver.catalog.Styles; import org.geoserver.data.test.SystemTestData; import org.geoserver.data.test.TestData; import org.geoserver.platform.GeoServerResourceLoader; import org.geoserver.platform.resource.Resource; import org.geoserver.rest.RestBaseController; import org.geotools.data.DataUtilities; import org.geotools.styling.Style; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringWriter; import java.net.URL; import java.util.List; import java.util.Properties; import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo; import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.Matchers.endsWith; import static org.junit.Assert.*; /** * Just ripped these tests from the existing rest test */ public class StyleControllerTest extends CatalogRESTTestSupport { @Before public void removeStyles() throws IOException { removeStyle("gs", "foo"); removeStyle(null, "foo"); } @Before public void addPondsStyle() throws IOException { getTestData().addStyle(SystemTestData.PONDS.getLocalPart(), getCatalog()); } @Before public void restoreLayers() throws IOException { revertLayer(SystemTestData.BASIC_POLYGONS); } @Test public void testGetAllAsXML() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH + "/styles.xml" ); List<StyleInfo> styles = catalog.getStyles(); assertXpathEvaluatesTo(""+styles.size(), "count(//style)", dom); } @Test public void testGetAllASJSON() throws Exception { JSON json = getAsJSON(RestBaseController.ROOT_PATH + "/styles.json"); List<StyleInfo> styles = catalog.getStyles(); assertEquals( styles.size(), ((JSONObject) json).getJSONObject("styles").getJSONArray("style").size()); } @Test public void testGetAllAsHTML() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH + "/styles.html"); print(dom); List<StyleInfo> styles = catalog.getStylesByWorkspace(CatalogFacade.NO_WORKSPACE); NodeList links = xp.getMatchingNodes("//html:a", dom); for ( int i = 0; i < styles.size(); i++ ) { StyleInfo s = styles.get( i ); Element link = (Element) links.item( i ); final String href = link.getAttribute("href"); assertTrue("Expected href to bed with " + s.getName() + ".html but was " + href, href.endsWith(s.getName() + ".html")); } } @Test public void testGetAllFromWorkspace() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH + "/workspaces/gs/styles.xml" ); assertEquals("styles", dom.getDocumentElement().getNodeName()); assertXpathEvaluatesTo("0", "count(//style)", dom); addStyleToWorkspace("foo"); dom = getAsDOM( RestBaseController.ROOT_PATH + "/workspaces/gs/styles.xml" ); assertEquals("styles", dom.getDocumentElement().getNodeName()); assertXpathEvaluatesTo("1", "count(//style)", dom); assertXpathExists("//style/name[text() = 'foo']", dom); } void addStyleToWorkspace(String name) { Catalog cat = getCatalog(); StyleInfo s = cat.getFactory().createStyle(); s.setName(name); s.setFilename(name + ".sld"); s.setWorkspace(cat.getWorkspaceByName("gs")); cat.add(s); } @Test public void testGetAsXML() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH + "/styles/Ponds.xml" ); assertEquals( "style", dom.getDocumentElement().getNodeName() ); assertXpathEvaluatesTo("Ponds", "/style/name", dom); assertXpathEvaluatesTo("Ponds.sld", "/style/filename", dom); } @Test public void testGetAsJSON() throws Exception { JSON json = getAsJSON( RestBaseController.ROOT_PATH + "/styles/Ponds.json"); JSONObject style = ((JSONObject)json).getJSONObject("style"); assertEquals( "Ponds", style.get( "name") ); assertEquals( "Ponds.sld", style.get( "filename") ); } @Test public void testGetWrongStyle() throws Exception { // Parameters for the request String ws = "gs"; String style = "foooooo"; // Request path String requestPath = RestBaseController.ROOT_PATH + "/styles/" + style + ".html"; String requestPath2 = RestBaseController.ROOT_PATH + "/workspaces/" + ws + "/styles/" + style + ".html"; // Exception path String exception = "No such style: " + style; String exception2 = "No such style "+ style +" in workspace " + ws; // CASE 1: No workspace set // First request should thrown an exception MockHttpServletResponse response = getAsServletResponse(requestPath); assertEquals(404, response.getStatus()); assertTrue(response.getContentAsString().contains( exception)); // Same request with ?quietOnNotFound should not throw an exception response = getAsServletResponse(requestPath + "?quietOnNotFound=true"); assertEquals(404, response.getStatus()); assertFalse(response.getContentAsString().contains( exception)); // No exception thrown assertTrue(response.getContentAsString().isEmpty()); // CASE 2: workspace set // First request should thrown an exception response = getAsServletResponse(requestPath2); assertEquals(404, response.getStatus()); assertTrue(response.getContentAsString().contains( exception2)); // Same request with ?quietOnNotFound should not throw an exception response = getAsServletResponse(requestPath2 + "?quietOnNotFound=true"); assertEquals(404, response.getStatus()); assertFalse(response.getContentAsString().contains( exception2)); // No exception thrown assertTrue(response.getContentAsString().isEmpty()); } @Test public void testGetAsSLD() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH + "/styles/Ponds.sld"); assertEquals( "StyledLayerDescriptor", dom.getDocumentElement().getNodeName() ); } @Test public void testGetFromWorkspace() throws Exception { MockHttpServletResponse resp = getAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml"); assertEquals(404, resp.getStatus()); addStyleToWorkspace("foo"); resp = getAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml"); assertEquals(200, resp.getStatus()); Document dom = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml"); assertXpathEvaluatesTo("foo", "/style/name", dom); assertXpathEvaluatesTo("gs", "/style/workspace/name", dom); } String newSLDXML() { return "<sld:StyledLayerDescriptor xmlns:sld='http://www.opengis.net/sld'>"+ "<sld:NamedLayer>"+ "<sld:Name>foo</sld:Name>"+ "<sld:UserStyle>"+ "<sld:Name>foo</sld:Name>"+ "<sld:FeatureTypeStyle>"+ "<sld:Name>foo</sld:Name>"+ "</sld:FeatureTypeStyle>" + "</sld:UserStyle>" + "</sld:NamedLayer>" + "</sld:StyledLayerDescriptor>"; } @Test public void testPostAsSLD() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles", xml, SLDHandler.MIMETYPE_10); assertEquals( 201, response.getStatus() ); assertNotNull( response.getHeader( "Location") ); assertTrue( response.getHeader("Location").endsWith( "/styles/foo" ) ); assertNotNull( catalog.getStyleByName( "foo" ) ); } @Test public void testPostExternalEntityAsSLD() throws Exception { String xml = IOUtils.toString(TestData.class.getResource("externalEntities.sld"), "UTF-8"); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles", xml, SLDHandler.MIMETYPE_10); assertEquals( 500, response.getStatus() ); String message = response.getContentAsString(); assertThat(message, containsString("Entity resolution disallowed")); assertThat(message, containsString("/this/file/does/not/exist")); } @Test public void testPostAsSLDToWorkspace() throws Exception { assertNull( catalog.getStyleByName( "gs", "foo" ) ); String xml = newSLDXML(); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/workspaces/gs/styles", xml, SLDHandler.MIMETYPE_10); assertEquals( 201, response.getStatus() ); assertNotNull( response.getHeader( "Location") ); assertTrue( response.getHeader("Location").endsWith( "/workspaces/gs/styles/foo" ) ); assertNotNull( catalog.getStyleByName( "gs", "foo" ) ); GeoServerResourceLoader rl = getResourceLoader(); assertNotNull(rl.find("workspaces", "gs", "styles", "foo.sld")); } @Test public void testPostAsSLDWithName() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles?name=bar", xml, SLDHandler.MIMETYPE_10); assertEquals( 201, response.getStatus() ); assertNotNull( response.getHeader( "Location") ); assertTrue( response.getHeader("Location").endsWith( "/styles/bar" ) ); assertNotNull( catalog.getStyleByName( "bar" ) ); } @Test public void testStyleWithSpaceInName() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles?name=Default%20Styler", xml, SLDHandler.MIMETYPE_10); assertEquals( 201, response.getStatus() ); assertNotNull( response.getHeader( "Location") ); assertThat(response.getHeader("Location"), endsWith( "/styles/Default%20Styler" ) ); assertNotNull( catalog.getStyleByName( "Default Styler" ) ); // now delete it, using a + instead of %20, the old code supported it response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Default+Styler"); assertEquals(200, response.getStatus()); } @Test public void testPostToWorkspace() throws Exception { Catalog cat = getCatalog(); assertNull(cat.getStyleByName("gs", "foo")); String xml = "<style>" + "<name>foo</name>" + "<filename>foo.sld</filename>" + "</style>"; MockHttpServletResponse response = postAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles", xml); assertEquals(201, response.getStatus()); assertNotNull(cat.getStyleByName("gs", "foo")); } @Test public void testPut() throws Exception { StyleInfo style = catalog.getStyleByName( "Ponds"); assertEquals( "Ponds.sld", style.getFilename() ); String xml = "<style>" + "<name>Ponds</name>" + "<filename>Forests.sld</filename>" + "</style>"; MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Ponds", xml.getBytes(), "text/xml"); assertEquals( 200, response.getStatus() ); style = catalog.getStyleByName( "Ponds"); assertEquals( "Forests.sld", style.getFilename() ); } @Test public void testPutAsSLD() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/styles/Ponds", xml, SLDHandler.MIMETYPE_10); assertEquals( 200, response.getStatus() ); Style s = catalog.getStyleByName( "Ponds" ).getStyle(); ByteArrayOutputStream out = new ByteArrayOutputStream(); SLDHandler handler = new SLDHandler(); handler.encode(Styles.sld(s), SLDHandler.VERSION_10, false, out); xml = new String(out.toByteArray()); assertTrue(xml.contains("<sld:Name>foo</sld:Name>")); } @Test public void testPutAsSLDWithExtension() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/styles/Ponds.sld", xml, SLDHandler.MIMETYPE_10); assertEquals( 200, response.getStatus() ); Style s = catalog.getStyleByName( "Ponds" ).getStyle(); ByteArrayOutputStream out = new ByteArrayOutputStream(); SLDHandler handler = new SLDHandler(); handler.encode(Styles.sld(s), SLDHandler.VERSION_10, false, out); xml = new String(out.toByteArray()); assertTrue(xml.contains("<sld:Name>foo</sld:Name>")); } @Test public void testRawPutAsSLD() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/styles/Ponds?raw=true", xml, SLDHandler.MIMETYPE_10); assertEquals( 200, response.getStatus() ); Style s = catalog.getStyleByName( "Ponds" ).getStyle(); ByteArrayOutputStream out = new ByteArrayOutputStream(); SLDHandler handler = new SLDHandler(); handler.encode(Styles.sld(s), SLDHandler.VERSION_10, false, out); xml = new String(out.toByteArray()); assertTrue(xml.contains("<sld:Name>foo</sld:Name>")); } @Test public void testRawPutAsInvalidSLD() throws Exception { String xml = "This is not valid SLD"; MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/styles/Ponds?raw=true", xml, SLDHandler.MIMETYPE_10); assertEquals( 200, response.getStatus() ); StyleInfo styleInfo = catalog.getStyleByName( "Ponds" ); String fileName = styleInfo.getFilename(); GeoServerResourceLoader resources = getGeoServer().getCatalog().getResourceLoader(); Resource resource = resources.get("styles/"+fileName); String content = new String(resource.getContents()); assertFalse("replaced",content.contains("<sld:Name>foo</sld:Name>")); assertTrue("replaced",content.contains("not valid")); } @Test public void testPutToWorkspace() throws Exception { testPostToWorkspace(); Catalog cat = getCatalog(); assertEquals("foo.sld", cat.getStyleByName("gs","foo").getFilename()); String xml = "<style>" + "<filename>bar.sld</filename>" + "</style>"; MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", xml, "application/xml"); assertEquals(200, response.getStatus()); assertEquals("bar.sld", cat.getStyleByName("gs","foo").getFilename()); } @Test public void testPutToWorkspaceChangeWorkspace() throws Exception { testPostToWorkspace(); String xml = "<style>" + "<workspace>cite</workspace>" + "</style>"; MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", xml, "application/xml"); assertEquals(403, response.getStatus()); } @Test public void testStyleNotFoundGloballyWhenInWorkspace() throws Exception { testPostToWorkspace(); Catalog cat = getCatalog(); assertEquals("foo.sld", cat.getStyleByName("gs","foo").getFilename()); String xml = "<style>" + "<filename>bar.sld</filename>" + "</style>"; MockHttpServletResponse response = putAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", xml, "application/xml"); assertEquals(200, response.getStatus()); response = putAsServletResponse(RestBaseController.ROOT_PATH + "/styles/gs:foo", xml, "application/xml"); assertEquals(500, response.getStatus()); } @Test public void testDelete() throws Exception { String xml = "<style>" + "<name>dummy</name>" + "<filename>dummy.sld</filename>" + "</style>"; post( RestBaseController.ROOT_PATH + "/styles", xml, "text/xml"); assertNotNull( catalog.getStyleByName( "dummy" ) ); MockHttpServletResponse response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/dummy"); assertEquals( 200, response.getStatus() ); assertNull( catalog.getStyleByName( "dummy" ) ); } @Test public void testDeleteWithLayerReference() throws Exception { assertNotNull( catalog.getStyleByName( "Ponds" ) ); MockHttpServletResponse response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Ponds"); assertEquals( 403, response.getStatus() ); assertNotNull( catalog.getStyleByName( "Ponds" ) ); } @Test public void testDeleteWithLayerReferenceAndRecurse() throws Exception { assertNotNull( catalog.getStyleByName( "Ponds" ) ); MockHttpServletResponse response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/Ponds?recurse=true"); assertEquals( 200, response.getStatus() ); assertNull( catalog.getStyleByName( "Ponds" ) ); } @Test public void testDeleteWithoutPurge() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles", xml, SLDHandler.MIMETYPE_10); assertNotNull( catalog.getStyleByName( "foo" ) ); //ensure the style not deleted on disk assertTrue(new File(getDataDirectory().findStyleDir(), "foo.sld").exists()); response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/foo"); assertEquals( 200, response.getStatus() ); //ensure the style deleted on disk but backed up assertFalse(new File(getDataDirectory().findStyleDir(), "foo.sld").exists()); assertTrue(new File(getDataDirectory().findStyleDir(), "foo.sld.bak").exists()); } @Test public void testDeleteWithPurge() throws Exception { String xml = newSLDXML(); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles", xml, SLDHandler.MIMETYPE_10); assertNotNull( catalog.getStyleByName( "foo" ) ); //ensure the style not deleted on disk assertTrue(new File(getDataDirectory().findStyleDir(), "foo.sld").exists()); response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/styles/foo?purge=true"); assertEquals( 200, response.getStatus() ); //ensure the style not deleted on disk assertFalse(new File(getDataDirectory().findStyleDir(), "foo.sld").exists()); } @Test public void testDeleteFromWorkspace() throws Exception { testPostToWorkspace(); Catalog cat = getCatalog(); assertNotNull(cat.getStyleByName("gs", "foo")); MockHttpServletResponse response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.xml"); assertEquals(200, response.getStatus()); assertNull(cat.getStyleByName("gs", "foo")); } @Test public void testDeleteFromWorkspaceWithPurge() throws Exception { testPostAsSLDToWorkspace(); Catalog cat = getCatalog(); assertNotNull(cat.getStyleByName("gs", "foo")); GeoServerResourceLoader rl = getResourceLoader(); assertNotNull(rl.find("workspaces", "gs", "styles", "foo.sld")); MockHttpServletResponse response = deleteAsServletResponse(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo?purge=true"); assertEquals(200, response.getStatus()); assertNull(cat.getStyleByName("gs", "foo")); assertNull(rl.find("workspaces", "gs", "styles", "foo.sld")); } @Test public void testGetAllByLayer() throws Exception { Document dom = getAsDOM( RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles.xml"); LayerInfo layer = catalog.getLayerByName( "cite:BasicPolygons" ); assertXpathEvaluatesTo(layer.getStyles().size()+"", "count(//style)", dom ); } @Test public void testPostByLayer() throws Exception { LayerInfo l = catalog.getLayerByName( "cite:BasicPolygons" ); int nstyles = l.getStyles().size(); String xml = "<style>" + "<name>Ponds</name>" + "</style>"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles", xml, "text/xml"); assertEquals( 201, response.getStatus() ); LayerInfo l2 = catalog.getLayerByName( "cite:BasicPolygons" ); assertEquals( nstyles+1, l2.getStyles().size() ); assertTrue( l2.getStyles().contains( catalog.getStyleByName( "Ponds") ) ); } @Test public void testPostByLayerWithDefault() throws Exception { getTestData().addVectorLayer(SystemTestData.BASIC_POLYGONS, getCatalog()); LayerInfo l = catalog.getLayerByName( "cite:BasicPolygons" ); int nstyles = l.getStyles().size(); String xml = "<style>" + "<name>Ponds</name>" + "</style>"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles?default=true", xml, "text/xml"); assertEquals( 201, response.getStatus() ); LayerInfo l2 = catalog.getLayerByName( "cite:BasicPolygons" ); assertEquals( nstyles+1, l2.getStyles().size() ); assertEquals( catalog.getStyleByName( "Ponds"), l2.getDefaultStyle() ); } @Test public void testPostByLayerExistingWithDefault() throws Exception { getTestData().addVectorLayer(SystemTestData.BASIC_POLYGONS, getCatalog()); testPostByLayer(); LayerInfo l = catalog.getLayerByName("cite:BasicPolygons"); int nstyles = l.getStyles().size(); String xml = "<style>" + "<name>Ponds</name>" + "</style>"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/layers/cite:BasicPolygons/styles?default=true", xml, "text/xml"); assertEquals( 201, response.getStatus() ); LayerInfo l2 = catalog.getLayerByName("cite:BasicPolygons"); assertEquals( nstyles, l2.getStyles().size() ); assertEquals( catalog.getStyleByName( "Ponds"), l2.getDefaultStyle() ); } @Test @Ignore public void testPostAsPSL() throws Exception { Properties props = new Properties(); props.put("type", "point"); props.put("color", "ff0000"); StringWriter out = new StringWriter(); props.store(out, "comment!"); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles?name=foo", out.toString(), PropertyStyleHandler.MIMETYPE); assertEquals( 201, response.getStatus() ); assertNotNull( response.getHeader( "Location") ); assertTrue( response.getHeader("Location").endsWith( "/styles/foo" ) ); assertNotNull( catalog.getStyleByName( "foo" ) ); Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo")); InputStream in = style.in(); props = new Properties(); try { props.load(in); assertEquals("point", props.getProperty("type")); } finally { in.close(); } in = style.in(); try { out = new StringWriter(); IOUtils.copy(in, out); assertFalse(out.toString().startsWith("#comment!")); } finally { in.close(); } } @Test @Ignore public void testPostAsPSLRaw() throws Exception { Properties props = new Properties(); props.put("type", "point"); props.put("color", "ff0000"); StringWriter out = new StringWriter(); props.store(out, "comment!"); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles?name=foo&raw=true", out.toString(), PropertyStyleHandler.MIMETYPE); assertEquals( 201, response.getStatus() ); assertNotNull( response.getHeader( "Location") ); assertTrue( response.getHeader("Location").endsWith( "/styles/foo" ) ); // check style on disk to ensure the exact contents was preserved Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo")); try (InputStream in = style.in()) { out = new StringWriter(); IOUtils.copy(in, out); assertTrue(out.toString().startsWith("#comment!")); } } @Test @Ignore public void testGetAsPSL() throws Exception { Properties props = new Properties(); props.load(get(RestBaseController.ROOT_PATH + "/styles/Ponds.properties")); assertEquals("polygon", props.getProperty("type")); } @Test @Ignore public void testPutAsPSL() throws Exception { testPostAsPSL(); Properties props = new Properties(); props.put("type", "line"); props.put("color", "00ff00"); StringWriter out = new StringWriter(); props.store(out, "comment!"); MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/styles/foo", out.toString(), PropertyStyleHandler.MIMETYPE); assertEquals( 200, response.getStatus() ); Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo")); InputStream in = style.in(); try { props = new Properties(); props.load(in); assertEquals("line", props.getProperty("type")); } finally { in.close(); } in = style.in(); try { out = new StringWriter(); IOUtils.copy(in, out); assertFalse(out.toString().startsWith("#comment!")); } finally { in.close(); } } @Test @Ignore public void testPutAsPSLRaw() throws Exception { testPostAsPSL(); Properties props = new Properties(); props.put("type", "line"); props.put("color", "00ff00"); StringWriter out = new StringWriter(); props.store(out, "comment!"); MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/styles/foo?raw=true", out.toString(), PropertyStyleHandler.MIMETYPE); assertEquals( 200, response.getStatus() ); Resource style = getDataDirectory().style(getCatalog().getStyleByName("foo")); InputStream in = style.in(); try { props = new Properties(); props.load(in); assertEquals("line", props.getProperty("type")); } finally { in.close(); } in = style.in(); try { out = new StringWriter(); IOUtils.copy(in, out); assertTrue(out.toString().startsWith("#comment!")); } finally { in.close(); } } @Test public void testPostAsSE() throws Exception { String xml = "<StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" " + " xmlns:se=\"http://www.opengis.net/se\" version=\"1.1.0\"> "+ " <NamedLayer> "+ " <UserStyle> "+ " <se:Name>UserSelection</se:Name> "+ " <se:FeatureTypeStyle> "+ " <se:Rule> "+ " <se:PolygonSymbolizer> "+ " <se:Fill> "+ " <se:SvgParameter name=\"fill\">#FF0000</se:SvgParameter> "+ " </se:Fill> "+ " </se:PolygonSymbolizer> "+ " </se:Rule> "+ " </se:FeatureTypeStyle> "+ " </UserStyle> "+ " </NamedLayer> "+ "</StyledLayerDescriptor>"; MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles?name=foo", xml, SLDHandler.MIMETYPE_11); assertEquals( 201, response.getStatus() ); assertNotNull( response.getHeader( "Location") ); assertTrue( response.getHeader("Location").endsWith( "/styles/foo" ) ); StyleInfo style = catalog.getStyleByName("foo"); assertNotNull(style); assertEquals("sld", style.getFormat()); assertEquals(SLDHandler.VERSION_11, style.getFormatVersion()); } @Test public void testPostToWorkspaceSLDPackage() throws Exception { Catalog cat = getCatalog(); assertNull(cat.getStyleByName("gs", "foo")); URL zip = getClass().getResource("test-data/foo.zip"); byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip)); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/workspaces/gs/styles", bytes, "application/zip"); assertEquals( 201, response.getStatus() ); assertNotNull(cat.getStyleByName("gs", "foo")); Document d = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.sld"); assertEquals( "StyledLayerDescriptor", d.getDocumentElement().getNodeName()); XpathEngine engine = XMLUnit.newXpathEngine(); NodeList list = engine.getMatchingNodes("//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource", d); assertEquals(1, list.getLength()); Element onlineResource = (Element)list.item(0); assertEquals("gear.png", onlineResource.getAttribute("xlink:href")); assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/gear.png")); assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/foo.sld")); } @Test public void testPostWithExternalEntities() throws Exception { URL zip = getClass().getResource("test-data/externalEntities.zip"); byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip)); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/workspaces/gs/styles", bytes, "application/zip"); // expecting a failure with explanation assertEquals(400, response.getStatus() ); final String content = response.getContentAsString(); assertThat(content, containsString("Entity resolution disallowed")); assertThat(content, containsString("/this/file/does/not/exist")); } @Test public void testPutToWorkspaceSLDPackage() throws Exception { testPostAsSLDToWorkspace(); Catalog cat = getCatalog(); assertNotNull(cat.getStyleByName("gs", "foo")); URL zip = getClass().getResource("test-data/foo.zip"); byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip)); MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo", bytes, "application/zip"); assertEquals( 200, response.getStatus() ); assertNotNull(cat.getStyleByName("gs", "foo")); Document d = getAsDOM(RestBaseController.ROOT_PATH + "/workspaces/gs/styles/foo.sld"); assertEquals( "StyledLayerDescriptor", d.getDocumentElement().getNodeName()); XpathEngine engine = XMLUnit.newXpathEngine(); NodeList list = engine.getMatchingNodes("//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource", d); assertEquals(1, list.getLength()); Element onlineResource = (Element)list.item(0); assertEquals("gear.png", onlineResource.getAttribute("xlink:href")); assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/gear.png")); assertNotNull(getCatalog().getResourceLoader().find("workspaces/gs/styles/foo.sld")); } @Test public void testPostSLDPackage() throws Exception { Catalog cat = getCatalog(); assertNull(cat.getStyleByName("foo")); URL zip = getClass().getResource("test-data/foo.zip"); byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip)); MockHttpServletResponse response = postAsServletResponse( RestBaseController.ROOT_PATH + "/styles", bytes, "application/zip"); assertEquals( 201, response.getStatus() ); assertNotNull(cat.getStyleByName("foo")); Document d = getAsDOM(RestBaseController.ROOT_PATH + "/styles/foo.sld"); assertEquals( "StyledLayerDescriptor", d.getDocumentElement().getNodeName()); XpathEngine engine = XMLUnit.newXpathEngine(); NodeList list = engine.getMatchingNodes("//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource", d); assertEquals(1, list.getLength()); Element onlineResource = (Element)list.item(0); assertEquals("gear.png", onlineResource.getAttribute("xlink:href")); assertNotNull(getCatalog().getResourceLoader().find("styles/gear.png")); assertNotNull(getCatalog().getResourceLoader().find("styles/foo.sld")); } @Test public void testPutSLDPackage() throws Exception { testPostAsSLD(); Catalog cat = getCatalog(); assertNotNull(cat.getStyleByName("foo")); URL zip = getClass().getResource("test-data/foo.zip"); byte[] bytes = FileUtils.readFileToByteArray(DataUtilities.urlToFile(zip)); //@TODO i had to change this from foo.zip to just foo. see the long comments below MockHttpServletResponse response = putAsServletResponse( RestBaseController.ROOT_PATH + "/styles/foo", bytes, "application/zip"); assertEquals( 200, response.getStatus() ); assertNotNull(cat.getStyleByName("foo")); Document d = getAsDOM(RestBaseController.ROOT_PATH + "/styles/foo.sld"); assertEquals( "StyledLayerDescriptor", d.getDocumentElement().getNodeName()); XpathEngine engine = XMLUnit.newXpathEngine(); NodeList list = engine.getMatchingNodes("//sld:StyledLayerDescriptor/sld:NamedLayer/sld:UserStyle/sld:FeatureTypeStyle/sld:Rule/sld:PointSymbolizer/sld:Graphic/sld:ExternalGraphic/sld:OnlineResource", d); assertEquals(1, list.getLength()); Element onlineResource = (Element)list.item(0); assertEquals("gear.png", onlineResource.getAttribute("xlink:href")); assertNotNull(getCatalog().getResourceLoader().find("styles/gear.png")); assertNotNull(getCatalog().getResourceLoader().find("styles/foo.sld")); } /** * TODO I had to put this here BECAUSE: * * - The testPutSLDPackage test uses a *.zip URL * - BUT, put style does not support ZIP responses * - Spring interprets the .zip extension on the path as being a request for a zip response * - This fails, because there is no actual handler for a zip response on a style endpoint * - Unfortunately Spring only considers one of the Accept header or the path * - So the handler is never found * * this leaves us with a few options * * 1) Configure spring to prefer the accept header over the path. This would: * * - Force future clients who depended on put/posting to zip endpoints to make sure their * Accept header is correct. * - Maybe more importantly it could potentially break other end points that depend on preferring * the path extension. * * 2) Continue letting Spring prefer the path (which is really the right behavior for a REST api) * * - Future clients would not be able to use an endpoint like .zip * - But this is more REST-y * * 3) Write our own content negotiation strategy that allows for both. * * - This is a pain in the ass. * - Potentially difficult to recreate all default behavior + behavior needed to fix this test * case * * @param path * @param body * @param contentType * @return * @throws Exception */ protected MockHttpServletResponse putAsServletResponse(String path, byte[] body, String contentType, String accepts) throws Exception { MockHttpServletRequest request = createRequest(path); request.setMethod("PUT"); request.setContentType(contentType); request.setContent(body); request.addHeader("Accept", accepts); request.addHeader("Content-type", contentType); return dispatch(request); } }