/* (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.JSONArray;
import net.sf.json.JSONObject;
import org.geoserver.catalog.CascadeDeleteVisitor;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.rest.RestBaseController;
import org.geotools.data.DataStore;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletResponse;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
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.geoserver.rest.RestBaseController.ROOT_PATH;
import static org.hamcrest.Matchers.endsWith;
import static org.junit.Assert.*;
public class DataStoreControllerTest extends CatalogRESTTestSupport {
@Before
public void addDataStores() throws IOException {
// the store configuration gets ruined by tests in more than one way, let's recreate it
DataStoreInfo sfStore = getCatalog().getDataStoreByName("sf");
if(sfStore != null) {
CascadeDeleteVisitor remover = new CascadeDeleteVisitor(getCatalog());
remover.visit(sfStore);
}
getTestData().addVectorLayer(SystemTestData.PRIMITIVEGEOFEATURE, catalog);
getTestData().addVectorLayer(SystemTestData.AGGREGATEGEOFEATURE, catalog);
getTestData().addVectorLayer(SystemTestData.GENERICENTITY, catalog);
}
@Test
public void testGetAllAsXML() throws Exception {
Document dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores.xml");
assertEquals( catalog.getStoresByWorkspace( "sf", DataStoreInfo.class ).size(),
dom.getElementsByTagName( "dataStore").getLength() );
}
@Test
public void testGetAsJSON() throws Exception {
JSON json = getAsJSON( ROOT_PATH+"/workspaces/sf/datastores/sf.json" );
JSONObject dataStore = ((JSONObject)json).getJSONObject("dataStore");
assertNotNull(dataStore);
assertEquals( "sf", dataStore.get( "name") );
assertEquals( "sf", dataStore.getJSONObject( "workspace").get( "name" ) );
assertNotNull( dataStore.get( "connectionParameters") );
}
@Test
public void testGetAllAsJSON() throws Exception {
JSON json = getAsJSON( ROOT_PATH+"/workspaces/sf/datastores.json");
assertTrue( json instanceof JSONObject );
Object datastores = ((JSONObject)json).getJSONObject("dataStores").get("dataStore");
assertNotNull( datastores );
if( datastores instanceof JSONArray ) {
assertEquals( catalog.getDataStoresByWorkspace("sf").size() , ((JSONArray)datastores).size() );
}
else {
assertEquals( 1, catalog.getDataStoresByWorkspace("sf").size() );
}
}
@Test
public void testGetAllAsHTML() throws Exception {
Document dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores.html");
List<DataStoreInfo> datastores = catalog.getDataStoresByWorkspace("sf");
NodeList links = xp.getMatchingNodes("//html:a", dom );
assertEquals( datastores.size(), links.getLength() );
for ( int i = 0; i < datastores.size(); i++ ){
DataStoreInfo ds = datastores.get( i );
Element link = (Element) links.item( i );
assertTrue( link.getAttribute("href").endsWith( ds.getName() + ".html") );
}
}
@Test
public void testPutAllUnauthorized() throws Exception {
assertEquals( 405, putAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores").getStatus() );
}
@Test
public void testDeleteAllUnauthorized() throws Exception {
assertEquals( 405, deleteAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores").getStatus() );
}
@Test
public void testGetAsXML() throws Exception {
Document dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.xml");
print(dom);
assertEquals( "dataStore", dom.getDocumentElement().getNodeName() );
assertEquals( "sf", xp.evaluate( "/dataStore/name", dom) );
assertEquals( "sf", xp.evaluate( "/dataStore/workspace/name", dom) );
assertXpathExists( "/dataStore/connectionParameters", dom );
assertThat( xp.evaluate( "/dataStore/featureTypes/atom:link/@href", dom), endsWith(RestBaseController.ROOT_PATH
+ "/workspaces/sf/datastores/sf/featuretypes.xml"));
}
@Test
public void testRoundTripGetAsXML() throws Exception {
Document dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.xml");
assertEquals( "dataStore", dom.getDocumentElement().getNodeName() );
assertEquals( "sf", xp.evaluate( "/dataStore/name", dom) );
assertEquals( "sf", xp.evaluate( "/dataStore/workspace/name", dom) );
assertXpathExists( "/dataStore/connectionParameters", dom );
Document dom2 = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.xml");
assertXpathEvaluatesTo("true", "/dataStore/enabled", dom );
String xml =
"<dataStore>" +
"<name>sf</name>" +
"<enabled>false</enabled>" +
"</dataStore>";
MockHttpServletResponse response =
putAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores/sf", xml, "text/xml");
assertEquals( 200, response.getStatus() );
dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.xml");
assertXpathEvaluatesTo("false", "/dataStore/enabled", dom );
assertFalse( catalog.getDataStoreByName( "sf", "sf").isEnabled() );
}
@Test
public void testGetAsHTML() throws Exception {
Document dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.html");
DataStoreInfo ds = catalog.getDataStoreByName( "sf" );
List<FeatureTypeInfo> featureTypes = catalog.getFeatureTypesByDataStore( ds );
NodeList links = xp.getMatchingNodes("//html:a", dom );
assertEquals( featureTypes.size(), links.getLength() );
for ( int i = 0; i < featureTypes.size(); i++ ){
FeatureTypeInfo ft = featureTypes.get( i );
Element link = (Element) links.item( i );
assertTrue( link.getAttribute("href").endsWith( ft.getName() + ".html") );
}
}
@Test
public void testGetWrongDataStore() throws Exception {
// Parameters for the request
String ws = "sf";
String ds = "sfssssss";
// Request path
String requestPath = ROOT_PATH+"/workspaces/" + ws + "/datastores/" + ds + ".html";
// Exception path
String exception = "No such datastore: " + ws + "," + ds;
// 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());
}
File setupNewDataStore() throws Exception {
Properties props = new Properties();
props.put( "_", "name:StringpointProperty:Point");
props.put( "NewDataStore.0", "'zero'|POINT(0 0)");
props.put( "NewDataStore.1", "'one'|POINT(1 1)");
File dir = new File( "./target/nds" );
dir.mkdir();
File file = new File( dir, "newDataStore.properties");
file.deleteOnExit();
dir.deleteOnExit();
props.store( new FileOutputStream( file ), null );
return dir;
}
@Test
public void testPostAsXML() throws Exception {
File dir = setupNewDataStore();
String xml =
"<dataStore>" +
"<name>newDataStore</name>" +
"<connectionParameters>" +
"<namespace><string>sf</string></namespace>" +
"<directory>" +
"<string>" + dir.getAbsolutePath() + "</string>" +
"</directory>" +
"</connectionParameters>" +
"<workspace>sf</workspace>" +
"</dataStore>";
MockHttpServletResponse response =
postAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores", xml, "text/xml" );
assertEquals( 201, response.getStatus() );
assertNotNull( response.getHeader( "Location") );
assertTrue( response.getHeader("Location").endsWith( "/workspaces/sf/datastores/newDataStore" ) );
DataStoreInfo newDataStore = catalog.getDataStoreByName( "newDataStore" );
assertNotNull( newDataStore );
DataStore ds = (DataStore) newDataStore.getDataStore(null);
assertNotNull(ds);
}
@Test
public void testPostAsXMLNoWorkspace() throws Exception {
File dir = setupNewDataStore();
String xml =
"<dataStore>" +
"<name>newDataStore</name>" +
"<connectionParameters>" +
"<namespace><string>sf</string></namespace>" +
"<directory>" +
"<string>" + dir.getAbsolutePath() + "</string>" +
"</directory>" +
"</connectionParameters>" +
"</dataStore>";
MockHttpServletResponse response =
postAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores", xml, "text/xml" );
assertEquals( 201, response.getStatus() );
assertNotNull( response.getHeader( "Location") );
assertTrue( response.getHeader("Location").endsWith( "/workspaces/sf/datastores/newDataStore" ) );
DataStoreInfo newDataStore = catalog.getDataStoreByName( "newDataStore" );
assertNotNull( newDataStore );
DataStore ds = (DataStore) newDataStore.getDataStore(null);
assertNotNull(ds);
}
@Test
public void testPostAsJSON() throws Exception {
removeStore("sf", "newDataStore");
File dir = setupNewDataStore();
String json =
"{'dataStore':{" +
"'connectionParameters': {" +
"'namespace': {'string':'sf'}," +
"'directory': {'string':'" + dir.getAbsolutePath().replace('\\','/') + "'}" +
"}," +
"'workspace':'sf'," +
"'name':'newDataStore'," +
"}" +
"}";
MockHttpServletResponse response =
postAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores", json, "text/json" );
assertEquals( 201, response.getStatus() );
assertNotNull( response.getHeader( "Location") );
assertTrue( response.getHeader("Location").endsWith( "/workspaces/sf/datastores/newDataStore" ) );
DataStoreInfo newDataStore = catalog.getDataStoreByName( "newDataStore" );
assertNotNull( newDataStore );
DataStore ds = (DataStore) newDataStore.getDataStore(null);
assertNotNull(ds);
}
@Test
public void testPostToResource() throws Exception {
String xml =
"<dataStore>" +
"<name>sf</name>" +
"<enabled>false</enabled>" +
"</dataStore>";
MockHttpServletResponse response =
postAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores/sf", xml, "text/xml");
assertEquals( 405, response.getStatus() );
}
@Test
public void testPut() throws Exception {
Document dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.xml");
assertXpathEvaluatesTo("true", "/dataStore/enabled", dom );
String xml =
"<dataStore>" +
"<name>sf</name>" +
"<enabled>false</enabled>" +
"</dataStore>";
MockHttpServletResponse response =
putAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores/sf", xml, "text/xml");
assertEquals( 200, response.getStatus() );
dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.xml");
assertXpathEvaluatesTo("false", "/dataStore/enabled", dom );
assertFalse( catalog.getDataStoreByName( "sf", "sf").isEnabled() );
}
@Test
public void testPut2() throws Exception {
Document dom = getAsDOM( ROOT_PATH+"/workspaces/sf/datastores/sf.xml");
assertXpathEvaluatesTo("2", "count(//dataStore/connectionParameters/*)", dom );
String xml =
"<dataStore>" +
"<name>sf</name>" +
"<connectionParameters>" +
"<one>" +
"<string>1</string>" +
"</one>" +
"<two>"+
"<string>2</string>" +
"</two>" +
"</connectionParameters>"+
"</dataStore>";
MockHttpServletResponse response =
putAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores/sf", xml, "text/xml");
assertEquals( 200, response.getStatus() );
DataStoreInfo ds = catalog.getDataStoreByName( "sf", "sf" );
assertEquals( 2, ds.getConnectionParameters().size() );
assertTrue( ds.getConnectionParameters().containsKey( "one" ) );
assertTrue( ds.getConnectionParameters().containsKey( "two" ) );
}
@Test
public void testPutNonDestructive() throws Exception {
DataStoreInfo ds = catalog.getDataStoreByName( "sf", "sf");
assertTrue(ds.isEnabled());
String xml =
"<dataStore>" +
"<name>sf</name>" +
"</dataStore>";
MockHttpServletResponse response =
putAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores/sf", xml, "text/xml");
assertEquals( 200, response.getStatus() );
assertTrue(ds.isEnabled());
}
@Test
public void testPutNonExistant() throws Exception {
String xml =
"<dataStore>" +
"<name>changed</name>" +
"</dataStore>";
MockHttpServletResponse response =
putAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores/nonExistant", xml, "text/xml" );
assertEquals( 404, response.getStatus() );
}
@Test
public void testDeleteNonExistant() throws Exception {
assertEquals( 404, deleteAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores/nonExistant").getStatus() );
}
@Test
public void testDelete() throws Exception {
removeStore("sf", "newDataStore");
File dir = setupNewDataStore();
String xml =
"<dataStore>" +
"<name>newDataStore</name>" +
"<connectionParameters>" +
"<entry>" +
"<string>namespace</string>" +
"<string>sf</string>" +
"</entry>" +
"<entry>" +
"<string>directory</string>" +
"<string>" + dir.getAbsolutePath() + "</string>" +
"</entry>" +
"</connectionParameters>" +
"<workspace>sf</workspace>" +
"</dataStore>";
MockHttpServletResponse response =
postAsServletResponse( ROOT_PATH+"/workspaces/sf/datastores", xml, "text/xml" );
assertEquals( 201, response.getStatus() );
assertNotNull( catalog.getDataStoreByName("sf", "newDataStore"));
assertEquals( 200, deleteAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores/newDataStore").getStatus());
assertNull( catalog.getDataStoreByName("sf", "newDataStore"));
}
@Test
public void testDeleteNonEmptyForbidden() throws Exception {
assertEquals( 403, deleteAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores/sf").getStatus());
}
@Test
public void testDeleteRecursive() throws Exception {
assertNotNull(catalog.getDataStoreByName("sf", "sf"));
MockHttpServletResponse response =
deleteAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores/sf?recurse=true");
assertEquals(200, response.getStatus());
assertNull(catalog.getDataStoreByName("sf", "sf"));
for (FeatureTypeInfo ft : catalog.getFeatureTypes()) {
if (ft.getStore().getName().equals("sf")) {
fail();
}
}
}
@Test
public void testPutNameChangeForbidden() throws Exception {
getTestData().addVectorLayer(SystemTestData.PRIMITIVEGEOFEATURE, getCatalog());
String xml = "<dataStore>" +
"<name>newName</name>" +
"</dataStore>";
assertEquals( 403, putAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores/sf", xml, "text/xml").getStatus());
}
@Test
public void testPutWorkspaceChangeForbidden() throws Exception {
String xml = "<dataStore>" +
"<workspace>gs</workspace>" +
"</dataStore>";
assertEquals( 403, putAsServletResponse(ROOT_PATH+"/workspaces/sf/datastores/sf", xml, "text/xml").getStatus());
}
}