/* (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.spatialite;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.impl.NamespaceInfoImpl;
import org.geoserver.catalog.impl.WorkspaceInfoImpl;
import org.geoserver.data.test.SystemTestData;
import org.geoserver.test.GeoServerSystemTestSupport;
import org.geoserver.util.IOUtils;
import org.geotools.data.DataAccess;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.DataUtilities;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.data.spatialite.SpatiaLiteDataStoreFactory;
import org.geotools.feature.NameImpl;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.Name;
import org.springframework.mock.web.MockHttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
/**
* Contains tests that invoke REST resources that will use SpatiaLite data store.
*/
public final class RestTest extends GeoServerSystemTestSupport {
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(RestTest.class);
private static final String SQLITE_MIME_TYPE = "application/x-sqlite3";
private static final String WORKSPACE_NAME = "spatialite-tests";
private static final String WORKSPACE_URI = "http://spatialite-tests.org";
private static File ROOT_DIRECTORY;
private static File DATABASE_FILE;
private static byte[] DATABASE_FILE_AS_BYTES;
@Override
protected void onSetUp(SystemTestData testData) throws Exception {
// create a test workspace
WorkspaceInfoImpl workspace = new WorkspaceInfoImpl();
workspace.setName(WORKSPACE_NAME);
getCatalog().add(workspace);
// create test workspace namespace
NamespaceInfoImpl nameSpace = new NamespaceInfoImpl();
nameSpace.setPrefix(WORKSPACE_NAME);
nameSpace.setURI(WORKSPACE_URI);
getCatalog().add(nameSpace);
}
@BeforeClass
public static void setUp() throws Throwable {
// make sure that SpatiaLite database are supported
boolean available = new SpatiaLiteDataStoreFactory().isAvailable();
if (!available) {
// SpatiaLite requires some native libraries to be installed
LOGGER.warning("SpatialLite data store is not available REST tests will not run, " +
"this is probably due to missing native libraries.");
}
Assume.assumeTrue(available);
// create root tests directory
ROOT_DIRECTORY = IOUtils.createTempDirectory("spatialite-tests");
// create the test database
DATABASE_FILE = new File(ROOT_DIRECTORY, UUID.randomUUID().toString() + ".db");
createTestDatabase();
// read the test SpatiaLite database file
DATABASE_FILE_AS_BYTES = readSqLiteDatabaseFile();
}
@AfterClass
public static void tearDown() throws Throwable {
// check if the root directory was initiated (test may have been skipped)
if (ROOT_DIRECTORY != null) {
// remove root tests directory
IOUtils.delete(ROOT_DIRECTORY);
}
}
@Before
public void login() {
// make sure we perform all requests logged as admin
login("admin", "geoserver", "ROLE_ADMINISTRATOR");
}
@Test
public void createDataStoreUsingRest() throws Exception {
String dataStoreName = UUID.randomUUID().toString();
// perform a PUT request, a new SpatiaLite data store should be created
// we require that all available feature types should be created
String path = String.format(
"/rest/workspaces/%s/datastores/%s/file.spatialite?configure=all", WORKSPACE_NAME, dataStoreName);
MockHttpServletResponse response = putAsServletResponse(path, DATABASE_FILE_AS_BYTES, SQLITE_MIME_TYPE);
// we should get a HTTP 201 status code meaning that the data store was created
assertThat(response.getStatus(), is(201));
// let's see if the data store was correctly created
DataStoreInfo storeInfo = getCatalog().getDataStoreByName(dataStoreName);
assertThat(storeInfo, notNullValue());
DataAccess store = storeInfo.getDataStore(null);
assertThat(store, notNullValue());
List<Name> names = store.getNames();
assertThat(store, notNullValue());
// check that at least the table points is available
Name found = names.stream()
.filter(name -> name != null && name.getLocalPart().equals("points"))
.findFirst().orElse(null);
assertThat(found, notNullValue());
// check that the points layer was correctly created
LayerInfo layerInfo = getCatalog().getLayerByName(new NameImpl(WORKSPACE_URI, "points"));
assertThat(layerInfo, notNullValue());
assertThat(layerInfo.getResource(), notNullValue());
assertThat(layerInfo.getResource(), instanceOf(FeatureTypeInfo.class));
// check that we have the expected features
FeatureTypeInfo featureTypeInfo = (FeatureTypeInfo) layerInfo.getResource();
int count = featureTypeInfo.getFeatureSource(null, null).getCount(Query.ALL);
assertThat(count, is(4));
}
/**
* Helper method that just creates the test data store using GeoTools APIs.
*/
private static void createTestDatabase() throws Exception {
// connect to the test data store
Map<String, String> params = new HashMap<>();
params.put("dbtype", "spatialite");
params.put("database", DATABASE_FILE.getAbsolutePath());
DataStore datastore = DataStoreFinder.getDataStore(params);
// create the points table (feature type)
SimpleFeatureType featureType = DataUtilities.createType("points", "id:Integer,name:String,geometry:Point:srid=4326");
datastore.createSchema(featureType);
// get write access to the data store
SimpleFeatureSource featureSource = datastore.getFeatureSource("points");
if (!(featureSource instanceof SimpleFeatureStore)) {
throw new RuntimeException("SpatiaLite data store doesn't support write access.");
}
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
Transaction transaction = new DefaultTransaction("create");
featureStore.setTransaction(transaction);
// create some features
SimpleFeatureCollection features = new ListFeatureCollection(featureType,
new SimpleFeature[]{
DataUtilities.createFeature(featureType, "1|point_a|POINT(-1,1)"),
DataUtilities.createFeature(featureType, "2|point_b|POINT(-1,-1)"),
DataUtilities.createFeature(featureType, "3|point_c|POINT(1,-1)"),
DataUtilities.createFeature(featureType, "4|point_d|POINT(1,1)"),
});
try {
// insert the features
featureStore.addFeatures(features);
transaction.commit();
} finally {
transaction.close();
}
}
/**
* Helper method that just reads the test SpatiaLite database file
* and stores it in a array of bytes.
*/
private static byte[] readSqLiteDatabaseFile() throws Exception {
// open the database file
InputStream input = new FileInputStream(DATABASE_FILE);
ByteArrayOutputStream output = new ByteArrayOutputStream();
try {
// copy the input stream to the output stream
IOUtils.copy(input, output);
} catch (Exception exception) {
throw new RuntimeException("Error reading SQLite database file to byte array.", exception);
}
return output.toByteArray();
}
}