http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e76b8d7/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java new file mode 100644 index 0000000..f35eeb7 --- /dev/null +++ b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java @@ -0,0 +1,362 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.rya.indexing.geotemporal.model; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.rya.api.domain.RyaURI; +import org.apache.rya.indexing.IndexingExpr; +import org.apache.rya.indexing.IndexingFunctionRegistry; +import org.apache.rya.indexing.IndexingFunctionRegistry.FUNCTION_TYPE; +import org.apache.rya.indexing.TemporalInstant; +import org.apache.rya.indexing.TemporalInstantRfc3339; +import org.apache.rya.indexing.geotemporal.mongo.MongoEventStorage; +import org.apache.rya.indexing.geotemporal.mongo.MongoITBase; +import org.apache.rya.indexing.geotemporal.storage.EventStorage; +import org.junit.Test; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.URIImpl; +import org.openrdf.model.impl.ValueFactoryImpl; +import org.openrdf.query.BindingSet; +import org.openrdf.query.QueryEvaluationException; +import org.openrdf.query.algebra.FunctionCall; +import org.openrdf.query.algebra.StatementPattern; +import org.openrdf.query.algebra.ValueConstant; +import org.openrdf.query.algebra.ValueExpr; +import org.openrdf.query.algebra.Var; +import org.openrdf.query.impl.MapBindingSet; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.PrecisionModel; + +import info.aduna.iteration.CloseableIteration; + +/** + * Unit tests the methods of {@link EventQueryNode}. + */ +public class EventQueryNodeTest extends MongoITBase { + private static final GeometryFactory GF = new GeometryFactory(new PrecisionModel(), 4326); + private static final ValueFactory VF = ValueFactoryImpl.getInstance(); + + @Test(expected = IllegalStateException.class) + public void constructor_differentSubjects() throws Exception { + final Var geoSubj = new Var("point"); + final Var geoPred = new Var("-const-http://www.opengis.net/ont/geosparql#asWKT", ValueFactoryImpl.getInstance().createURI("http://www.opengis.net/ont/geosparql#asWKT")); + final Var geoObj = new Var("wkt"); + final StatementPattern geoSP = new StatementPattern(geoSubj, geoPred, geoObj); + + final Var timeSubj = new Var("time"); + final Var timePred = new Var("-const-http://www.w3.org/2006/time#inXSDDateTime", ValueFactoryImpl.getInstance().createURI("-const-http://www.w3.org/2006/time#inXSDDateTime")); + final Var timeObj = new Var("time"); + final StatementPattern timeSP = new StatementPattern(timeSubj, timePred, timeObj); + // This will fail. + new EventQueryNode.EventQueryNodeBuilder() + .setStorage(mock(EventStorage.class)) + .setGeoPattern(geoSP) + .setTemporalPattern(timeSP) + .setGeoFilters(new ArrayList<IndexingExpr>()) + .setTemporalFilters(new ArrayList<IndexingExpr>()) + .setUsedFilters(new ArrayList<>()) + .build(); + } + + @Test(expected = IllegalStateException.class) + public void constructor_variablePredicate() throws Exception { + // A pattern that has a variable for its predicate. + final Var geoSubj = new Var("point"); + final Var geoPred = new Var("geo"); + final Var geoObj = new Var("wkt"); + final StatementPattern geoSP = new StatementPattern(geoSubj, geoPred, geoObj); + + final Var timeSubj = new Var("time"); + final Var timePred = new Var("-const-http://www.w3.org/2006/time#inXSDDateTime", ValueFactoryImpl.getInstance().createURI("-const-http://www.w3.org/2006/time#inXSDDateTime")); + final Var timeObj = new Var("time"); + final StatementPattern timeSP = new StatementPattern(timeSubj, timePred, timeObj); + // This will fail. + new EventQueryNode.EventQueryNodeBuilder() + .setStorage(mock(EventStorage.class)) + .setGeoPattern(geoSP) + .setTemporalPattern(timeSP) + .setGeoFilters(new ArrayList<IndexingExpr>()) + .setTemporalFilters(new ArrayList<IndexingExpr>()) + .setUsedFilters(new ArrayList<>()) + .build(); + } + + @Test + public void evaluate_constantSubject() throws Exception { + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), "testDB"); + RyaURI subject = new RyaURI("urn:event-1111"); + final Geometry geo = GF.createPoint(new Coordinate(1, 1)); + final TemporalInstant temp = new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0); + final Event event = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + subject = new RyaURI("urn:event-2222"); + final Event otherEvent = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + storage.create(event); + storage.create(otherEvent); + + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?event ?time ?point ?wkt " + + "WHERE { " + + " <urn:event-1111> time:atTime ?time . " + + " <urn:event-1111> geo:asWKT ?wkt . " + + " FILTER(geof:sfWithin(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(tempo:equals(?time, \"" + temp.toString() + "\")) " + + "}"; + + final EventQueryNode node = buildNode(storage, query); + final CloseableIteration<BindingSet, QueryEvaluationException> rez = node.evaluate(new MapBindingSet()); + final MapBindingSet expected = new MapBindingSet(); + expected.addBinding("wkt", VF.createLiteral("POINT (1 1)")); + expected.addBinding("time", VF.createLiteral(temp.toString())); + int count = 0; + assertTrue(rez.hasNext()); + while(rez.hasNext()) { + assertEquals(expected, rez.next()); + count++; + } + assertEquals(1, count); + } + + @Test + public void evaluate_variableSubject() throws Exception { + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), "testDB"); + RyaURI subject = new RyaURI("urn:event-1111"); + Geometry geo = GF.createPoint(new Coordinate(1, 1)); + final TemporalInstant temp = new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0); + final Event event = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + subject = new RyaURI("urn:event-2222"); + geo = GF.createPoint(new Coordinate(-1, -1)); + final Event otherEvent = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + storage.create(event); + storage.create(otherEvent); + + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?event ?time ?point ?wkt " + + "WHERE { " + + " ?event time:atTime ?time . " + + " ?event geo:asWKT ?wkt . " + + " FILTER(geof:sfWithin(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(tempo:equals(?time, \"2015-12-30T12:00:00Z\")) " + + "}"; + + final EventQueryNode node = buildNode(storage, query); + final CloseableIteration<BindingSet, QueryEvaluationException> rez = node.evaluate(new MapBindingSet()); + final MapBindingSet expected1 = new MapBindingSet(); + expected1.addBinding("wkt", VF.createLiteral("POINT (1 1)")); + expected1.addBinding("time", VF.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString())); + final MapBindingSet expected2 = new MapBindingSet(); + expected2.addBinding("wkt", VF.createLiteral("POINT (-1 -1)")); + expected2.addBinding("time", VF.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString())); + + final List<BindingSet> actual = new ArrayList<>(); + while(rez.hasNext()) { + actual.add(rez.next()); + } + assertEquals(expected1, actual.get(0)); + assertEquals(expected2, actual.get(1)); + assertEquals(2, actual.size()); + } + + @Test + public void evaluate_variableSubject_existingBindingset() throws Exception { + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), "testDB"); + RyaURI subject = new RyaURI("urn:event-1111"); + Geometry geo = GF.createPoint(new Coordinate(1, 1)); + final TemporalInstant temp = new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0); + final Event event = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + subject = new RyaURI("urn:event-2222"); + geo = GF.createPoint(new Coordinate(-1, -1)); + final Event otherEvent = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + storage.create(event); + storage.create(otherEvent); + + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?event ?time ?point ?wkt " + + "WHERE { " + + " ?event time:atTime ?time . " + + " ?event geo:asWKT ?wkt . " + + " FILTER(geof:sfWithin(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(tempo:equals(?time, \"2015-12-30T12:00:00Z\")) " + + "}"; + + final EventQueryNode node = buildNode(storage, query); + final MapBindingSet existingBindings = new MapBindingSet(); + existingBindings.addBinding("event", VF.createURI("urn:event-2222")); + final CloseableIteration<BindingSet, QueryEvaluationException> rez = node.evaluate(existingBindings); + final MapBindingSet expected = new MapBindingSet(); + expected.addBinding("wkt", VF.createLiteral("POINT (-1 -1)")); + expected.addBinding("time", VF.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString())); + + final List<BindingSet> actual = new ArrayList<>(); + while(rez.hasNext()) { + actual.add(rez.next()); + } + assertEquals(1, actual.size()); + assertEquals(expected, actual.get(0)); + } + + @Test + public void evaluate_variableSubject_existingBindingsetWrongFilters() throws Exception { + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), "testDB"); + RyaURI subject = new RyaURI("urn:event-1111"); + Geometry geo = GF.createPoint(new Coordinate(1, 1)); + final TemporalInstant temp = new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0); + final Event event = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + subject = new RyaURI("urn:event-2222"); + geo = GF.createPoint(new Coordinate(-10, -10)); + final Event otherEvent = Event.builder() + .setSubject(subject) + .setGeometry(geo) + .setTemporalInstant(temp) + .build(); + + storage.create(event); + storage.create(otherEvent); + + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?event ?time ?point ?wkt " + + "WHERE { " + + " ?event time:atTime ?time . " + + " ?event geo:asWKT ?wkt . " + + " FILTER(geof:sfWithin(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(tempo:equals(?time, \"2015-12-30T12:00:00Z\")) " + + "}"; + + final EventQueryNode node = buildNode(storage, query); + final MapBindingSet existingBindings = new MapBindingSet(); + existingBindings.addBinding("event", VF.createURI("urn:event-2222")); + final CloseableIteration<BindingSet, QueryEvaluationException> rez = node.evaluate(existingBindings); + final MapBindingSet expected = new MapBindingSet(); + expected.addBinding("wkt", VF.createLiteral("POINT (-1 -1)")); + expected.addBinding("time", VF.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString())); + + assertFalse(rez.hasNext()); + } + + private EventQueryNode buildNode(final EventStorage store, final String query) throws Exception { + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + final URI filterURI = new URIImpl(filter.getURI()); + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(filterURI, filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(filterURI, sps.get(0), extractArguments(objVar.getName(), filter)); + if(IndexingFunctionRegistry.getFunctionType(filterURI) == FUNCTION_TYPE.GEO) { + geoFilters.add(expr); + } else { + temporalFilters.add(expr); + } + } + + final StatementPattern geoPattern = sps.get(1); + final StatementPattern temporalPattern = sps.get(0); + + return new EventQueryNode.EventQueryNodeBuilder() + .setStorage(store) + .setGeoPattern(geoPattern) + .setTemporalPattern(temporalPattern) + .setGeoFilters(geoFilters) + .setTemporalFilters(temporalFilters) + .setUsedFilters(filters) + .build(); + } + + private Value[] extractArguments(final String matchName, final FunctionCall call) { + final Value args[] = new Value[call.getArgs().size() - 1]; + int argI = 0; + for (int i = 0; i != call.getArgs().size(); ++i) { + final ValueExpr arg = call.getArgs().get(i); + if (argI == i && arg instanceof Var && matchName.equals(((Var)arg).getName())) { + continue; + } + if (arg instanceof ValueConstant) { + args[argI] = ((ValueConstant)arg).getValue(); + } else if (arg instanceof Var && ((Var)arg).hasValue()) { + args[argI] = ((Var)arg).getValue(); + } else { + throw new IllegalArgumentException("Query error: Found " + arg + ", expected a Literal, BNode or URI"); + } + ++argI; + } + return args; + } +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e76b8d7/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/EventDocumentConverterTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/EventDocumentConverterTest.java b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/EventDocumentConverterTest.java new file mode 100644 index 0000000..3f2f9d5 --- /dev/null +++ b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/EventDocumentConverterTest.java @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.rya.indexing.geotemporal.mongo; + +import static org.junit.Assert.assertEquals; + +import org.apache.rya.api.domain.RyaURI; +import org.apache.rya.indexing.TemporalInstant; +import org.apache.rya.indexing.TemporalInstantRfc3339; +import org.apache.rya.indexing.entity.storage.mongo.DocumentConverter.DocumentConverterException; +import org.apache.rya.indexing.geotemporal.model.Event; +import org.apache.rya.indexing.geotemporal.mongo.EventDocumentConverter; +import org.bson.Document; +import org.joda.time.DateTime; +import org.junit.Test; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.PrecisionModel; + +/** + * Tests the methods of {@link EventDocumentConverter}. + */ +public class EventDocumentConverterTest { + private static final GeometryFactory GF = new GeometryFactory(new PrecisionModel(), 4326); + + @Test + public void to_and_from_document() throws DocumentConverterException { + final Geometry geo = GF.createPoint(new Coordinate(10, 10)); + final TemporalInstant instant = new TemporalInstantRfc3339(DateTime.now()); + + // An Event that will be stored. + final Event event = Event.builder() + .setSubject(new RyaURI("urn:event/001")) + .setGeometry(geo) + .setTemporalInstant(instant) + .build(); + + final Document document = new EventDocumentConverter().toDocument(event); + + // Convert the Document back into an Event. + final Event converted = new EventDocumentConverter().fromDocument(document); + + // Ensure the original matches the round trip converted Event. + assertEquals(event, converted); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e76b8d7/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java new file mode 100644 index 0000000..4a31599 --- /dev/null +++ b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java @@ -0,0 +1,490 @@ +/* +l * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.rya.indexing.geotemporal.mongo; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.rya.api.resolver.RdfToRyaConversions; +import org.apache.rya.indexing.GeoConstants; +import org.apache.rya.indexing.IndexingExpr; +import org.apache.rya.indexing.IndexingFunctionRegistry; +import org.apache.rya.indexing.IndexingFunctionRegistry.FUNCTION_TYPE; +import org.apache.rya.indexing.geotemporal.GeoTemporalIndexer.GeoPolicy; +import org.apache.rya.indexing.geotemporal.GeoTemporalIndexer.TemporalPolicy; +import org.apache.rya.indexing.geotemporal.GeoTemporalTestBase; +import org.junit.Before; +import org.junit.Test; +import org.openrdf.model.Resource; +import org.openrdf.model.Statement; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.ContextStatementImpl; +import org.openrdf.model.impl.URIImpl; +import org.openrdf.model.impl.ValueFactoryImpl; +import org.openrdf.query.algebra.FunctionCall; +import org.openrdf.query.algebra.StatementPattern; +import org.openrdf.query.algebra.ValueConstant; +import org.openrdf.query.algebra.ValueExpr; +import org.openrdf.query.algebra.Var; + +import com.mongodb.DBObject; +import com.mongodb.util.JSON; + +/** + * Tests The {@link GeoTemporalMongoDBStorageStrategy}, which turns the filters + * into mongo {@link DBObject}s used to query. + * + * This tests also ensures all possible filter functions are accounted for in the test. + * @see TemporalPolicy Temporal Filter Functions + * @see GeoPolicy Geo Filter Functions + */ +public class GeoTemporalMongoDBStorageStrategyTest extends GeoTemporalTestBase { + private GeoTemporalMongoDBStorageStrategy adapter; + @Before + public void setup() { + adapter = new GeoTemporalMongoDBStorageStrategy(); + } + + @Test + public void emptyFilters_test() throws Exception { + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + final String expectedString = + "{ }"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void equalsInstantAfterInterval_onlyOneGeo() throws Exception { + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?point ?wkt " + + "WHERE { " + + " ?point geo:asWKT ?wkt . " + + " FILTER(geof:sfWithin(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + "}"; + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + //should only be one. + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(new URIImpl(filter.getURI()), filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(new URIImpl(filter.getURI()), sps.get(0), extractArguments(objVar.getName(), filter)); + geoFilters.add(expr); + } + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + final String expectedString = + "{ " + + "\"location\" : { " + + "\"$geoWithin\" : { " + + "\"$geometry\" : { " + + "\"coordinates\" : [ [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]] , " + + "\"type\" : \"Polygon\"" + + "}" + + "}" + + "}" + + "}"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void equalsInstantAfterInterval_onlyGeos() throws Exception { + + /* + * TODO: change filter functions for coverage + */ + + + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?point ?wkt " + + "WHERE { " + + " ?point geo:asWKT ?wkt . " + + " FILTER(geof:sfIntersects(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(geof:sfEquals(?wkt, \"POLYGON((-4 -3, -4 3, 2 3, 2 -3, -4 -3))\"^^geo:wktLiteral)) " + + "}"; + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(new URIImpl(filter.getURI()), filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(new URIImpl(filter.getURI()), sps.get(0), extractArguments(objVar.getName(), filter)); + geoFilters.add(expr); + } + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + + final String expectedString = + "{ " + + "\"$and\" : [ { " + + "\"location\" : {" + + " \"coordinates\" : [ [ [ -4.0 , -3.0] , [ -4.0 , 3.0] , [ 2.0 , 3.0] , [ 2.0 , -3.0] , [ -4.0 , -3.0]]] ," + + " \"type\" : \"Polygon\"" + + "}" + + "} , { " + + "\"location\" : { " + + "\"$geoIntersects\" : {" + + " \"$geometry\" : {" + + " \"coordinates\" : [ [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]] ," + + " \"type\" : \"Polygon\"" + + "}" + + "}" + + "}" + + "}]}"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void equalsInstantAfterInterval_onlyOneTemporal() throws Exception { + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "SELECT ?event ?time " + + "WHERE { " + + " ?event time:atTime ?time . " + + " FILTER(tempo:equals(?time, \"2015-12-30T12:00:00Z\")) . " + + "}"; + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + //should only be one. + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(new URIImpl(filter.getURI()), filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(new URIImpl(filter.getURI()), sps.get(0), extractArguments(objVar.getName(), filter)); + temporalFilters.add(expr); + } + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + final String expectedString = + "{ " + + "\"instant\" : {" + + "\"$date\" : \"2015-12-30T12:00:00.000Z\"" + + "}" + + "}"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void equalsInstantAfterInterval_onlyTemporal() throws Exception { + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "SELECT ?event ?time " + + "WHERE { " + + " ?event time:atTime ?time . " + + " FILTER(tempo:before(?time, \"2015-12-30T12:00:00Z\")) . " + + " FILTER(tempo:insideInterval(?time, \"[1969-12-31T19:00:00-05:00,1969-12-31T19:00:01-05:00]\")) . " + + "}"; + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(new URIImpl(filter.getURI()), filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(new URIImpl(filter.getURI()), sps.get(0), extractArguments(objVar.getName(), filter)); + temporalFilters.add(expr); + } + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + final String expectedString = + "{ " + + "\"$and\" : [{" + + "\"instant\" : {" + + "\"$gt\" : {" + + "\"$date\" : \"1970-01-01T00:00:00.000Z\"" + + "}," + + "\"$lt\" : {" + + "\"$date\" : \"1970-01-01T00:00:01.000Z\"" + + "}," + + "}}, {" + + "\"instant\" : {" + + "\"$lt\" : {" + + "\"$date\" : \"2015-12-30T12:00:00.000Z\"" + + "}" + + "}" + + "}]" + + "}"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void equalsInstantAfterInterval_GeoTemporalOneEach() throws Exception { + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?event ?time ?point ?wkt " + + "WHERE { " + + " ?event time:atTime ?time . " + + " ?point geo:asWKT ?wkt . " + + " FILTER(geof:sfWithin(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(tempo:after(?time, \"2015-12-30T12:00:00Z\")) " + + "}"; + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + final URI filterURI = new URIImpl(filter.getURI()); + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(filterURI, filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(filterURI, sps.get(0), extractArguments(objVar.getName(), filter)); + if(IndexingFunctionRegistry.getFunctionType(filterURI) == FUNCTION_TYPE.GEO) { + geoFilters.add(expr); + } else { + temporalFilters.add(expr); + } + } + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + final String expectedString = + "{ " + + "\"$and\" : [ { " + + "\"location\" : { " + + "\"$geoWithin\" : { " + + "\"$geometry\" : { " + + "\"coordinates\" : [ [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]] , " + + "\"type\" : \"Polygon\"" + + "}" + + "}" + + "}" + + "} , { " + + "\"instant\" : { " + + "\"$gt\" : { " + + "\"$date\" : \"2015-12-30T12:00:00.000Z\"" + + "}" + + "}" + + "}]" + + "}"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void equalsInstantAfterInterval_GeoTemporalTwoEach() throws Exception { + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?event ?time ?point ?wkt " + + "WHERE { " + + " ?event time:atTime ?time . " + + " ?point geo:asWKT ?wkt . " + + " FILTER(geof:sfWithin(?wkt, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(geof:sfEquals(?wkt, \"POLYGON((-4 -3, -4 3, 2 3, 2 -3, -4 -3))\"^^geo:wktLiteral)) " + + " FILTER(tempo:hasEndInterval(?time, \"[1969-12-31T19:00:00-05:00,1969-12-31T19:00:01-05:00]\")) . " + + " FILTER(tempo:beforeInterval(?time, \"[1969-12-31T19:00:00-05:00,1969-12-31T19:00:01-05:00]\")) . " + + "}"; + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + final URI filterURI = new URIImpl(filter.getURI()); + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(filterURI, filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(filterURI, sps.get(0), extractArguments(objVar.getName(), filter)); + if(IndexingFunctionRegistry.getFunctionType(filterURI) == FUNCTION_TYPE.GEO) { + geoFilters.add(expr); + } else { + temporalFilters.add(expr); + } + } + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + final String expectedString = + "{ " + + "\"$and\" : [ { " + + "\"$and\" : [ { " + + "\"location\" : { " + + "\"coordinates\" : [ [ [ -4.0 , -3.0] , [ -4.0 , 3.0] , [ 2.0 , 3.0] , [ 2.0 , -3.0] , [ -4.0 , -3.0]]] , " + + "\"type\" : \"Polygon\"" + + "}" + + "} , { " + + "\"location\" : { " + + "\"$geoWithin\" : { " + + "\"$geometry\" : { " + + "\"coordinates\" : [ [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]] , " + + "\"type\" : \"Polygon\"" + + "}" + + "}" + + "}" + + "}]" + + "} , { " + + "\"$and\" : [ { " + + "\"instant\" : { " + + "\"$lt\" : { " + + "\"$date\" : \"1970-01-01T00:00:00.000Z\"" + + "}" + + "}" + + "} , { " + + "\"instant\" : { " + + "\"$date\" : \"1970-01-01T00:00:01.000Z\"" + + "}" + + "}]" + + "}]" + + "}"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void equalsInstantAfterInterval_GeoTemporalSingleGeoTwoTemporal() throws Exception { + final String query = + "PREFIX time: <http://www.w3.org/2006/time#> \n" + + "PREFIX tempo: <tag:rya-rdf.org,2015:temporal#> \n" + + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geof: <http://www.opengis.net/def/function/geosparql/>" + + "SELECT ?event ?time ?point ?wkt " + + "WHERE { " + + " ?event time:atTime ?time . " + + " ?point geo:asWKT ?wkt . " + + " FILTER(geof:sfEquals(?wkt, \"POLYGON((-4 -3, -4 3, 2 3, 2 -3, -4 -3))\"^^geo:wktLiteral)) ." + + " FILTER(tempo:hasBeginningInterval(?time, \"[1969-12-31T19:00:00-05:00,1969-12-31T19:00:01-05:00]\")) . " + + " FILTER(tempo:afterInterval(?time, \"[1969-12-31T19:00:00-05:00,1969-12-31T19:00:01-05:00]\"))" + + "}"; + final List<IndexingExpr> geoFilters = new ArrayList<>(); + final List<IndexingExpr> temporalFilters = new ArrayList<>(); + final List<StatementPattern> sps = getSps(query); + final List<FunctionCall> filters = getFilters(query); + for(final FunctionCall filter : filters) { + final URI filterURI = new URIImpl(filter.getURI()); + final Var objVar = IndexingFunctionRegistry.getResultVarFromFunctionCall(filterURI, filter.getArgs()); + final IndexingExpr expr = new IndexingExpr(filterURI, sps.get(0), extractArguments(objVar.getName(), filter)); + if(IndexingFunctionRegistry.getFunctionType(filterURI) == FUNCTION_TYPE.GEO) { + geoFilters.add(expr); + } else { + temporalFilters.add(expr); + } + } + final DBObject actual = adapter.getFilterQuery(geoFilters, temporalFilters); + final String expectedString = + "{ " + + "\"$and\" : [ { " + + "\"location\" : { " + + "\"coordinates\" : [ [ [ -4.0 , -3.0] , [ -4.0 , 3.0] , [ 2.0 , 3.0] , [ 2.0 , -3.0] , [ -4.0 , -3.0]]] , " + + "\"type\" : \"Polygon\"" + + "}" + + "} , { " + + "\"$and\" : [ { " + + "\"instant\" : { " + + "\"$gt\" : { " + + "\"$date\" : \"1970-01-01T00:00:01.000Z\"" + + "}" + + "}" + + "} , { " + + "\"instant\" : { " + + "\"$date\" : \"1970-01-01T00:00:00.000Z\"" + + "}" + + "}]" + + "}]" + + "}"; + final DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + @Test + public void serializeTest() { + final ValueFactory vf = new ValueFactoryImpl(); + final Resource subject = vf.createURI("foo:subj"); + final Resource context = vf.createURI("foo:context"); + + //GEO + URI predicate = GeoConstants.GEO_AS_WKT; + Value object = vf.createLiteral("Point(-77.03524 38.889468)", GeoConstants.XMLSCHEMA_OGC_WKT); + + Statement statement = new ContextStatementImpl(subject, predicate, object, context); + DBObject actual = adapter.serialize(RdfToRyaConversions.convertStatement(statement)); + String expectedString = + "{ " + + "\"_id\" : -852305321 , " + + "\"location\" : { " + + "\"coordinates\" : [ -77.03524 , 38.889468] , " + + "\"type\" : \"Point\"" + + "}" + + "}"; + DBObject expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + + //TIME INSTANT + predicate = new URIImpl("Property:event:time"); + object = vf.createLiteral("2015-12-30T12:00:00Z"); + statement = new ContextStatementImpl(subject, predicate, object, context); + actual = adapter.serialize(RdfToRyaConversions.convertStatement(statement)); + expectedString = + "{" + +"_id : -852305321, " + +"time: {" + + "instant : {" + +"\"$date\" : \"2015-12-30T12:00:00.000Z\"" + + "}" + + "}" + + "}"; + expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + + //TIME INTERVAL + predicate = new URIImpl("Property:circa"); + object = vf.createLiteral("[1969-12-31T19:00:00-05:00,1969-12-31T19:00:01-05:00]"); + statement = new ContextStatementImpl(subject, predicate, object, context); + actual = adapter.serialize(RdfToRyaConversions.convertStatement(statement)); + expectedString = + "{" + +"_id : -852305321, " + +"time: {" + + "start : {" + +"\"$date\" : \"1970-01-01T00:00:00.000Z\"" + + "}," + + "end : {" + +"\"$date\" : \"1970-01-01T00:00:01.000Z\"" + + "}" + + "}" + + "}"; + expected = (DBObject) JSON.parse(expectedString); + assertEqualMongo(expected, actual); + } + + private Value[] extractArguments(final String matchName, final FunctionCall call) { + final Value args[] = new Value[call.getArgs().size() - 1]; + int argI = 0; + for (int i = 0; i != call.getArgs().size(); ++i) { + final ValueExpr arg = call.getArgs().get(i); + if (argI == i && arg instanceof Var && matchName.equals(((Var)arg).getName())) { + continue; + } + if (arg instanceof ValueConstant) { + args[argI] = ((ValueConstant)arg).getValue(); + } else if (arg instanceof Var && ((Var)arg).hasValue()) { + args[argI] = ((Var)arg).getValue(); + } else { + throw new IllegalArgumentException("Query error: Found " + arg + ", expected a Literal, BNode or URI"); + } + ++argI; + } + return args; + } +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e76b8d7/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoEventStorageTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoEventStorageTest.java b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoEventStorageTest.java new file mode 100644 index 0000000..5b07460 --- /dev/null +++ b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoEventStorageTest.java @@ -0,0 +1,197 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.rya.indexing.geotemporal.mongo; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Optional; + +import org.apache.rya.api.domain.RyaURI; +import org.apache.rya.indexing.TemporalInstant; +import org.apache.rya.indexing.TemporalInstantRfc3339; +import org.apache.rya.indexing.geotemporal.model.Event; +import org.apache.rya.indexing.geotemporal.storage.EventStorage; +import org.apache.rya.indexing.geotemporal.storage.EventStorage.EventAlreadyExistsException; +import org.apache.rya.indexing.geotemporal.storage.EventStorage.EventStorageException; +import org.joda.time.DateTime; +import org.junit.Test; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.PrecisionModel; + +/** + * Integration tests the methods of {@link MongoEventStorage}. + */ +public class MongoEventStorageTest extends MongoITBase { + + private static final String RYA_INSTANCE_NAME = "testInstance"; + private static final GeometryFactory GF = new GeometryFactory(new PrecisionModel(), 4326); + + @Test + public void create_and_get() throws Exception { + final Geometry geo = GF.createPoint(new Coordinate(10, 10)); + final TemporalInstant instant = new TemporalInstantRfc3339(DateTime.now()); + + // An Event that will be stored. + final Event event = Event.builder() + .setSubject(new RyaURI("urn:event/001")) + .setGeometry(geo) + .setTemporalInstant(instant) + .build(); + + // Create it. + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), RYA_INSTANCE_NAME); + storage.create(event); + + // Get it. + final Optional<Event> storedEvent = storage.get(new RyaURI("urn:event/001")); + + // Verify the correct value was returned. + assertEquals(event, storedEvent.get()); + } + + @Test + public void can_not_create_with_same_subject() throws Exception { + final Geometry geo = GF.createPoint(new Coordinate(10, 10)); + final TemporalInstant instant = new TemporalInstantRfc3339(DateTime.now()); + + // An Event that will be stored. + final Event event = Event.builder() + .setSubject(new RyaURI("urn:event/001")) + .setGeometry(geo) + .setTemporalInstant(instant) + .build(); + + // Create it. + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), RYA_INSTANCE_NAME); + storage.create(event); + + // Try to create it again. This will fail. + boolean failed = false; + try { + storage.create(event); + } catch(final EventAlreadyExistsException e) { + failed = true; + } + assertTrue(failed); + } + + @Test + public void get_noneExisting() throws Exception { + // Get a Type that hasn't been created. + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), RYA_INSTANCE_NAME); + final Optional<Event> storedEvent = storage.get(new RyaURI("urn:event/000")); + + // Verify nothing was returned. + assertFalse(storedEvent.isPresent()); + } + + @Test + public void delete() throws Exception { + final Geometry geo = GF.createPoint(new Coordinate(10, 10)); + final TemporalInstant instant = new TemporalInstantRfc3339(DateTime.now()); + + // An Event that will be stored. + final Event event = Event.builder() + .setSubject(new RyaURI("urn:event/002")) + .setGeometry(geo) + .setTemporalInstant(instant) + .build(); + + // Create it. + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), RYA_INSTANCE_NAME); + storage.create(event); + + // Delete it. + final boolean deleted = storage.delete( new RyaURI("urn:event/002") ); + + // Verify a document was deleted. + assertTrue( deleted ); + } + + @Test + public void delete_nonExisting() throws Exception { + // Delete an Event that has not been created. + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), RYA_INSTANCE_NAME); + final boolean deleted = storage.delete( new RyaURI("urn:event/003") ); + + // Verify no document was deleted. + assertFalse( deleted ); + } + + @Test + public void update() throws Exception { + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), RYA_INSTANCE_NAME); + final Geometry geo = GF.createPoint(new Coordinate(10, 10)); + TemporalInstant instant = new TemporalInstantRfc3339(DateTime.now()); + + // An Event that will be stored. + final Event event = Event.builder() + .setSubject(new RyaURI("urn:event/004")) + .setGeometry(geo) + .setTemporalInstant(instant) + .build(); + + storage.create(event); + + // Show Alice was stored. + Optional<Event> latest = storage.get(new RyaURI("urn:event/004")); + assertEquals(event, latest.get()); + + instant = new TemporalInstantRfc3339(DateTime.now()); + // Change Alice's eye color to brown. + final Event updated = Event.builder(event) + .setTemporalInstant(instant) + .build(); + + storage.update(event, updated); + + // Fetch the Alice object and ensure it has the new value. + latest = storage.get(new RyaURI("urn:event/004")); + + assertEquals(updated, latest.get()); + } + + @Test(expected = EventStorageException.class) + public void update_differentSubjects() throws Exception { + final EventStorage storage = new MongoEventStorage(super.getMongoClient(), RYA_INSTANCE_NAME); + final Geometry geo = GF.createPoint(new Coordinate(10, 10)); + final TemporalInstant instant = new TemporalInstantRfc3339(DateTime.now()); + + // Two objects that do not have the same Subjects. + final Event old = Event.builder() + .setSubject(new RyaURI("urn:event/001")) + .setGeometry(geo) + .setTemporalInstant(instant) + .build(); + + final Event updated = Event.builder() + .setSubject(new RyaURI("urn:event/002")) + .setGeometry(geo) + .setTemporalInstant(instant) + .build(); + + // The update will fail. + storage.update(old, updated); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e76b8d7/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java new file mode 100644 index 0000000..f2d0868 --- /dev/null +++ b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java @@ -0,0 +1,115 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.rya.indexing.geotemporal.mongo; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Optional; + +import org.apache.rya.api.domain.RyaStatement; +import org.apache.rya.api.resolver.RdfToRyaConversions; +import org.apache.rya.indexing.GeoConstants; +import org.apache.rya.indexing.TemporalInstant; +import org.apache.rya.indexing.geotemporal.model.Event; +import org.apache.rya.indexing.geotemporal.storage.EventStorage; +import org.junit.Before; +import org.junit.Test; +import org.openrdf.model.Resource; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.StatementImpl; +import org.openrdf.model.impl.ValueFactoryImpl; + +import com.vividsolutions.jts.geom.Geometry; + +/** + * Integration tests the methods of {@link MongoGeoTemporalIndexer}. + */ +public class MongoGeoTemporalIndexerIT extends MongoITBase { + private MongoGeoTemporalIndexer indexer; + + @Before + public void makeTestIndexer() throws Exception { + indexer = new MongoGeoTemporalIndexer(); + indexer.setConf(conf); + indexer.init(); + } + + @Test + public void ensureEvent() throws Exception { + final RyaStatement geoStmnt = statement(point(0, 0)); + final RyaStatement timeStmnt = statement(makeInstant(0)); + + final EventStorage store = indexer.getEventStorage(conf); + + indexer.storeStatement(geoStmnt); + Optional<Event> evnt = store.get(geoStmnt.getSubject()); + assertTrue(evnt.isPresent()); + Event expected = Event.builder() + .setSubject(geoStmnt.getSubject()) + .setGeometry(point(0, 0)) + .build(); + assertEquals(expected, evnt.get()); + + indexer.storeStatement(timeStmnt); + evnt = store.get(timeStmnt.getSubject()); + assertTrue(evnt.isPresent()); + expected = Event.builder() + .setSubject(geoStmnt.getSubject()) + .setGeometry(point(0, 0)) + .setTemporalInstant(makeInstant(0)) + .build(); + assertEquals(expected, evnt.get()); + + indexer.deleteStatement(geoStmnt); + evnt = store.get(timeStmnt.getSubject()); + assertTrue(evnt.isPresent()); + expected = Event.builder() + .setSubject(timeStmnt.getSubject()) + .setTemporalInstant(makeInstant(0)) + .build(); + assertEquals(expected, evnt.get()); + + indexer.deleteStatement(timeStmnt); + evnt = store.get(timeStmnt.getSubject()); + assertTrue(evnt.isPresent()); + expected = Event.builder() + .setSubject(timeStmnt.getSubject()) + .build(); + assertEquals(expected, evnt.get()); + } + + private static RyaStatement statement(final Geometry geo) { + final ValueFactory vf = new ValueFactoryImpl(); + final Resource subject = vf.createURI("uri:test"); + final URI predicate = GeoConstants.GEO_AS_WKT; + final Value object = vf.createLiteral(geo.toString(), GeoConstants.XMLSCHEMA_OGC_WKT); + return RdfToRyaConversions.convertStatement(new StatementImpl(subject, predicate, object)); + } + + private static RyaStatement statement(final TemporalInstant instant) { + final ValueFactory vf = new ValueFactoryImpl(); + final Resource subject = vf.createURI("uri:test"); + final URI predicate = vf.createURI("Property:atTime"); + final Value object = vf.createLiteral(instant.toString()); + return RdfToRyaConversions.convertStatement(new StatementImpl(subject, predicate, object)); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e76b8d7/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java new file mode 100644 index 0000000..7488572 --- /dev/null +++ b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.rya.indexing.geotemporal.mongo; + +import org.apache.rya.indexing.accumulo.ConfigUtils; +import org.apache.rya.indexing.geotemporal.GeoTemporalTestBase; +import org.apache.rya.indexing.mongodb.MongoIndexingConfiguration; +import org.apache.rya.mongodb.MockMongoSingleton; +import org.junit.After; +import org.junit.Before; + +import com.mongodb.MongoClient; + +/** + * A base class that may be used when implementing Mongo DB integration tests that + * use the JUnit framework. + */ +public class MongoITBase extends GeoTemporalTestBase { + + private static MongoClient mongoClient = null; + protected static MongoIndexingConfiguration conf; + + @Before + public void setupTest() throws Exception { + mongoClient = MockMongoSingleton.getInstance(); + conf = MongoIndexingConfiguration.builder() + .setMongoCollectionPrefix("test_") + .setMongoDBName("testDB") + .build(); + conf.setBoolean(ConfigUtils.USE_MONGO, true); + conf.setMongoClient(mongoClient); + } + + @After + public void cleanupTest() { + // Remove any DBs that were created by the test. + for(final String dbName : mongoClient.listDatabaseNames()) { + mongoClient.dropDatabase(dbName); + } + } + + /** + * @return A {@link MongoClient} that is connected to the embedded instance of Mongo DB. + */ + public MongoClient getMongoClient() { + return mongoClient; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/9e76b8d7/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/mongo/MongoGeoIndexerSfTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/mongo/MongoGeoIndexerSfTest.java b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/mongo/MongoGeoIndexerSfTest.java new file mode 100644 index 0000000..57873fd --- /dev/null +++ b/extras/rya.geoindexing/geo.mongo/src/test/java/org/apache/rya/indexing/mongo/MongoGeoIndexerSfTest.java @@ -0,0 +1,262 @@ +package org.apache.rya.indexing.mongo; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static org.apache.rya.indexing.GeoIndexingTestUtils.getSet; + +import java.util.Map; +import java.util.Set; + +import org.apache.rya.api.domain.RyaStatement; +import org.apache.rya.api.resolver.RdfToRyaConversions; +import org.apache.rya.api.resolver.RyaToRdfConversions; +import org.apache.rya.indexing.GeoConstants; +import org.apache.rya.indexing.StatementConstraints; +import org.apache.rya.indexing.accumulo.ConfigUtils; +import org.apache.rya.indexing.geotemporal.mongo.MongoITBase; +import org.apache.rya.indexing.accumulo.geo.OptionalConfigUtils; +import org.apache.rya.indexing.mongodb.geo.MongoGeoIndexer; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.openrdf.model.Resource; +import org.openrdf.model.Statement; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.StatementImpl; +import org.openrdf.model.impl.ValueFactoryImpl; + +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.PrecisionModel; + +import info.aduna.iteration.CloseableIteration; + +/** + * Tests all of the "simple functions" of the geoindexer. + */ +public class MongoGeoIndexerSfTest extends MongoITBase { + private static GeometryFactory gf = new GeometryFactory(new PrecisionModel(), 4326); + private static MongoGeoIndexer g; + + private static final StatementConstraints EMPTY_CONSTRAINTS = new StatementConstraints(); + + // Here is the landscape: + /** + * <pre> + * +---+---+---+---+---+---+---+ + * | F | | + * + A + + C + + * | | | + * +---+---+ E +---+---+ + * | | / | + * + B + /+---+---+ + * | | / | | + * +---+---+/--+---+---+ + * / | D | + * / +---+---+ + * </pre> + **/ + + private static final Polygon A = poly(bbox(0, 1, 4, 5)); + private static final Polygon B = poly(bbox(0, 1, 2, 3)); + private static final Polygon C = poly(bbox(4, 3, 6, 5)); + private static final Polygon D = poly(bbox(3, 0, 5, 2)); + + private static final Point F = point(2, 4); + + private static final LineString E = line(2, 0, 3, 3); + + private static final Map<Geometry, String> names = Maps.newHashMap(); + static { + names.put(A, "A"); + names.put(B, "B"); + names.put(C, "C"); + names.put(D, "D"); + names.put(E, "E"); + names.put(F, "F"); + } + + @Before + public void before() throws Exception { + conf.set(ConfigUtils.GEO_PREDICATES_LIST, "http://www.opengis.net/ont/geosparql#asWKT"); + conf.set(OptionalConfigUtils.USE_GEO, "true"); + + g = new MongoGeoIndexer(); + g.initIndexer(conf, super.getMongoClient()); + g.storeStatement(statement(A)); + g.storeStatement(statement(B)); + g.storeStatement(statement(C)); + g.storeStatement(statement(D)); + g.storeStatement(statement(F)); + g.storeStatement(statement(E)); + } + + private static RyaStatement statement(final Geometry geo) { + final ValueFactory vf = new ValueFactoryImpl(); + final Resource subject = vf.createURI("uri:" + names.get(geo)); + final URI predicate = GeoConstants.GEO_AS_WKT; + final Value object = vf.createLiteral(geo.toString(), GeoConstants.XMLSCHEMA_OGC_WKT); + return RdfToRyaConversions.convertStatement(new StatementImpl(subject, predicate, object)); + + } + + public void compare(final CloseableIteration<Statement, ?> actual, final Geometry... expected) throws Exception { + final Set<Statement> expectedSet = Sets.newHashSet(); + for (final Geometry geo : expected) { + expectedSet.add(RyaToRdfConversions.convertStatement(statement(geo))); + } + + Assert.assertEquals(expectedSet, getSet(actual)); + } + + private static Geometry[] EMPTY_RESULTS = {}; + + @Test + public void testEquals() throws Exception { + // point + compare(g.queryEquals(F, EMPTY_CONSTRAINTS), F); + compare(g.queryEquals(point(2, 2), EMPTY_CONSTRAINTS), EMPTY_RESULTS); + + // line + compare(g.queryEquals(E, EMPTY_CONSTRAINTS), E); + compare(g.queryEquals(line(2, 2, 3, 3), EMPTY_CONSTRAINTS), EMPTY_RESULTS); + + // poly + compare(g.queryEquals(A, EMPTY_CONSTRAINTS), A); + compare(g.queryEquals(poly(bbox(1, 1, 4, 5)), EMPTY_CONSTRAINTS), EMPTY_RESULTS); + + } + +// @Test +// public void testDisjoint() throws Exception { +// // point +// compare(g.queryDisjoint(F, EMPTY_CONSTRAINTS), B, C, D, E); +// +// // line +// compare(g.queryDisjoint(E, EMPTY_CONSTRAINTS), B, C, D, F); +// +// // poly +// compare(g.queryDisjoint(A, EMPTY_CONSTRAINTS), EMPTY_RESULTS); +// compare(g.queryDisjoint(B, EMPTY_CONSTRAINTS), C, D, F, E); +// } + + @Test + public void testIntersectsPoint() throws Exception { + // This seems like a bug + // compare(g.queryIntersects(F, EMPTY_CONSTRAINTS), A, F); + // compare(g.queryIntersects(F, EMPTY_CONSTRAINTS), EMPTY_RESULTS); + } + + @Test + public void testIntersectsLine() throws Exception { + // This seems like a bug + // compare(g.queryIntersects(E, EMPTY_CONSTRAINTS), A, E); + // compare(g.queryIntersects(E, EMPTY_CONSTRAINTS), EMPTY_RESULTS); + } + +// @Test +// public void testIntersectsPoly() throws Exception { +// compare(g.queryIntersects(A, EMPTY_CONSTRAINTS), A, B, C, D, F, E); +// } + +// @Test +// public void testTouchesPoint() throws Exception { +// compare(g.queryTouches(F, EMPTY_CONSTRAINTS), EMPTY_RESULTS); +// } +// +// @Test +// public void testTouchesLine() throws Exception { +// compare(g.queryTouches(E, EMPTY_CONSTRAINTS), EMPTY_RESULTS); +// } + +// @Test +// public void testTouchesPoly() throws Exception { +// compare(g.queryTouches(A, EMPTY_CONSTRAINTS), C); +// } + +// @Test +// public void testCrossesPoint() throws Exception { +// compare(g.queryCrosses(F, EMPTY_CONSTRAINTS), EMPTY_RESULTS); +// } + + @Test + public void testCrossesLine() throws Exception { + // compare(g.queryCrosses(E, EMPTY_CONSTRAINTS), A); + } + +// @Test +// public void testCrossesPoly() throws Exception { +// compare(g.queryCrosses(A, EMPTY_CONSTRAINTS), E); +// } + +// @Test +// public void testWithin() throws Exception { +// // point +// // compare(g.queryWithin(F, EMPTY_CONSTRAINTS), F); +// +// // line +//// compare(g.queryWithin(E, EMPTY_CONSTRAINTS), E); +// +// // poly +// compare(g.queryWithin(A, EMPTY_CONSTRAINTS), A, B, F); +// } + +// @Test +// public void testContainsPoint() throws Exception { +// compare(g.queryContains(F, EMPTY_CONSTRAINTS), A, F); +// } + + @Test + public void testContainsLine() throws Exception { + // compare(g.queryContains(E, EMPTY_CONSTRAINTS), E); + } + +// @Test +// public void testContainsPoly() throws Exception { +// compare(g.queryContains(A, EMPTY_CONSTRAINTS), A); +// compare(g.queryContains(B, EMPTY_CONSTRAINTS), A, B); +// } + + @Test + public void testOverlapsPoint() throws Exception { + // compare(g.queryOverlaps(F, EMPTY_CONSTRAINTS), F); + // You cannot have overlapping points + // compare(g.queryOverlaps(F, EMPTY_CONSTRAINTS), EMPTY_RESULTS); + } + + @Test + public void testOverlapsLine() throws Exception { + // compare(g.queryOverlaps(E, EMPTY_CONSTRAINTS), A, E); + // You cannot have overlapping lines + // compare(g.queryOverlaps(E, EMPTY_CONSTRAINTS), EMPTY_RESULTS); + } + +// @Test +// public void testOverlapsPoly() throws Exception { +// compare(g.queryOverlaps(A, EMPTY_CONSTRAINTS), D); +// } + +}