http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalProviderTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalProviderTest.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalProviderTest.java new file mode 100644 index 0000000..7151b56 --- /dev/null +++ b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalProviderTest.java @@ -0,0 +1,222 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; + +import java.util.List; + +import org.apache.rya.indexing.GeoConstants; +import org.apache.rya.indexing.TemporalInstantRfc3339; +import org.apache.rya.indexing.external.matching.QuerySegment; +import org.apache.rya.indexing.geotemporal.GeoTemporalIndexSetProvider; +import org.apache.rya.indexing.geotemporal.model.EventQueryNode; +import org.apache.rya.indexing.geotemporal.storage.EventStorage; +import org.junit.Before; +import org.junit.Test; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.ValueFactoryImpl; + +public class GeoTemporalProviderTest extends GeoTemporalTestBase { + private static final String URI_PROPERTY_AT_TIME = "Property:atTime"; + private GeoTemporalIndexSetProvider provider; + private EventStorage events; + @Before + public void setup() { + events = mock(EventStorage.class); + provider = new GeoTemporalIndexSetProvider(events); + } + + /* + * Simplest Happy Path test + */ + @Test + public void twoPatternsTwoFilters_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final Value geo = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + final Value temp = vf.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX time: <tag:rya-rdf.org,2015:temporal#>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + "?subj <" + GeoConstants.GEO_AS_WKT + "> ?loc . " + + " FILTER(geos:sfContains(?loc, " + geo + ")) . " + + " FILTER(time:equals(?time, " + temp + ")) . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(1, nodes.size()); + } + + @Test + public void onePatternTwoFilters_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final Value geo = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + final Value temp = vf.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX time: <tag:rya-rdf.org,2015:temporal#>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + " FILTER(geos:sfContains(?loc, " + geo + ")) . " + + " FILTER(time:equals(?time, " + temp + ")) . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(0, nodes.size()); + } + + @Test + public void twoPatternsOneFilter_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final Value geo = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + final Value temp = vf.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX time: <tag:rya-rdf.org,2015:temporal#>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + "?subj <" + GeoConstants.GEO_AS_WKT + "> ?loc . " + + " FILTER(geos:sfContains(?loc, " + geo + ")) . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(0, nodes.size()); + } + + @Test + public void twoPatternsNoFilter_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX time: <tag:rya-rdf.org,2015:temporal#>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + "?subj <" + GeoConstants.GEO_AS_WKT + "> ?loc . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(0, nodes.size()); + } + + @Test + public void twoPatternsTwoFiltersNotValid_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final Value geo = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + final Value temp = vf.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + //Only handles geo and temporal filters + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX text: <http://rdf.useekm.com/fts#text>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + "?subj <" + GeoConstants.GEO_AS_WKT + "> ?loc . " + + " FILTER(geos:sfContains(?loc, " + geo + ")) . " + + " FILTER(text:equals(?time, " + temp + ")) . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(0, nodes.size()); + } + + @Test + public void twoSubjOneFilter_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final Value geo = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + final Value temp = vf.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX time: <tag:rya-rdf.org,2015:temporal#>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + "?subj <" + GeoConstants.GEO_AS_WKT + "> ?loc . " + + "?subj2 <" + tempPred + "> ?time2 ."+ + "?subj2 <" + GeoConstants.GEO_AS_WKT + "> ?loc2 . " + + " FILTER(geos:sfContains(?loc, " + geo + ")) . " + + " FILTER(time:equals(?time, " + temp + ")) . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(1, nodes.size()); + } + + @Test + public void twoNode_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final Value geo = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + final Value temp = vf.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX time: <tag:rya-rdf.org,2015:temporal#>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + "?subj <" + GeoConstants.GEO_AS_WKT + "> ?loc . " + + "?subj2 <" + tempPred + "> ?time2 ."+ + "?subj2 <" + GeoConstants.GEO_AS_WKT + "> ?loc2 . " + + " FILTER(geos:sfContains(?loc, " + geo + ")) . " + + " FILTER(time:equals(?time, " + temp + ")) . " + + " FILTER(geos:sfContains(?loc2, " + geo + ")) . " + + " FILTER(time:equals(?time2, " + temp + ")) . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(2, nodes.size()); + } + + @Test + public void twoSubjectMultiFilter_test() throws Exception { + final ValueFactory vf = new ValueFactoryImpl(); + final Value geo = vf.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + final Value temp = vf.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + final URI tempPred = vf.createURI(URI_PROPERTY_AT_TIME); + final String query = + "PREFIX geo: <http://www.opengis.net/ont/geosparql#>" + + "PREFIX geos: <http://www.opengis.net/def/function/geosparql/>" + + "PREFIX time: <tag:rya-rdf.org,2015:temporal#>" + + "SELECT * WHERE { " + + "?subj <" + tempPred + "> ?time ."+ + "?subj <" + GeoConstants.GEO_AS_WKT + "> ?loc . " + + " FILTER(geos:sfContains(?loc, " + geo + ")) . " + + " FILTER(time:equals(?time, " + temp + ")) . " + + " FILTER(geos:sfWithin(?loc, " + geo + ")) . " + + " FILTER(time:before(?time, " + temp + ")) . " + + "}"; + final QuerySegment<EventQueryNode> node = getQueryNode(query); + final List<EventQueryNode> nodes = provider.getExternalSets(node); + assertEquals(1, nodes.size()); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalTestBase.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalTestBase.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalTestBase.java new file mode 100644 index 0000000..6b6bf15 --- /dev/null +++ b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/GeoTemporalTestBase.java @@ -0,0 +1,140 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.rya.indexing.TemporalInstant; +import org.apache.rya.indexing.TemporalInstantRfc3339; +import org.apache.rya.indexing.external.matching.QuerySegment; +import org.apache.rya.indexing.geotemporal.model.EventQueryNode; +import org.junit.ComparisonFailure; +import org.mockito.Mockito; +import org.openrdf.query.algebra.FunctionCall; +import org.openrdf.query.algebra.QueryModelNode; +import org.openrdf.query.algebra.StatementPattern; +import org.openrdf.query.algebra.helpers.QueryModelVisitorBase; +import org.openrdf.query.algebra.helpers.StatementPatternCollector; +import org.openrdf.query.parser.sparql.SPARQLParser; + +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.LineString; +import com.vividsolutions.jts.geom.LinearRing; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.geom.PrecisionModel; +import com.vividsolutions.jts.geom.impl.PackedCoordinateSequence; + +public class GeoTemporalTestBase { + private static final GeometryFactory gf = new GeometryFactory(new PrecisionModel(), 4326); + + /** + * Make an uniform instant with given seconds. + */ + protected static TemporalInstant makeInstant(final int secondsMakeMeUnique) { + return new TemporalInstantRfc3339(2015, 12, 30, 12, 00, secondsMakeMeUnique); + } + + protected static Polygon poly(final double[] arr) { + final LinearRing r1 = gf.createLinearRing(new PackedCoordinateSequence.Double(arr, 2)); + final Polygon p1 = gf.createPolygon(r1, new LinearRing[] {}); + return p1; + } + + protected static Point point(final double x, final double y) { + return gf.createPoint(new Coordinate(x, y)); + } + + protected static LineString line(final double x1, final double y1, final double x2, final double y2) { + return new LineString(new PackedCoordinateSequence.Double(new double[] { x1, y1, x2, y2 }, 2), gf); + } + + protected static double[] bbox(final double x1, final double y1, final double x2, final double y2) { + return new double[] { x1, y1, x1, y2, x2, y2, x2, y1, x1, y1 }; + } + + protected void assertEqualMongo(final Object expected, final Object actual) throws ComparisonFailure { + try { + assertEquals(expected, actual); + } catch(final Throwable e) { + throw new ComparisonFailure(e.getMessage(), expected.toString(), actual.toString()); + } + } + + public List<FunctionCall> getFilters(final String query) throws Exception { + final FunctionCallCollector collector = new FunctionCallCollector(); + new SPARQLParser().parseQuery(query, null).getTupleExpr().visit(collector); + return collector.getTupleExpr(); + } + + public List<StatementPattern> getSps(final String query) throws Exception { + final StatementPatternCollector collector = new StatementPatternCollector(); + new SPARQLParser().parseQuery(query, null).getTupleExpr().visit(collector); + return collector.getStatementPatterns(); + } + + public QuerySegment<EventQueryNode> getQueryNode(final String query) throws Exception { + final List<QueryModelNode> exprs = getNodes(query); + final QuerySegment<EventQueryNode> node = Mockito.mock(QuerySegment.class); + //provider only cares about Ordered nodes. + Mockito.when(node.getOrderedNodes()).thenReturn(exprs); + return node; + } + + private static List<QueryModelNode> getNodes(final String sparql) throws Exception { + final NodeCollector collector = new NodeCollector(); + new SPARQLParser().parseQuery(sparql, null).getTupleExpr().visit(collector); + return collector.getTupleExpr(); + } + + private static class NodeCollector extends QueryModelVisitorBase<RuntimeException> { + private final List<QueryModelNode> stPatterns = new ArrayList<>(); + + public List<QueryModelNode> getTupleExpr() { + return stPatterns; + } + + @Override + public void meet(final FunctionCall node) { + stPatterns.add(node); + } + + @Override + public void meet(final StatementPattern node) { + stPatterns.add(node); + } + } + + private static class FunctionCallCollector extends QueryModelVisitorBase<RuntimeException> { + private final List<FunctionCall> filters = new ArrayList<>(); + + public List<FunctionCall> getTupleExpr() { + return filters; + } + + @Override + public void meet(final FunctionCall node) { + filters.add(node); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/MongoGeoTemporalIndexIT.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/MongoGeoTemporalIndexIT.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/MongoGeoTemporalIndexIT.java new file mode 100644 index 0000000..66de3fa --- /dev/null +++ b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/MongoGeoTemporalIndexIT.java @@ -0,0 +1,174 @@ +/** + * 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; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import org.apache.rya.api.RdfCloudTripleStoreConfiguration; +import org.apache.rya.api.domain.RyaURI; +import org.apache.rya.indexing.GeoConstants; +import org.apache.rya.indexing.GeoRyaSailFactory; +import org.apache.rya.indexing.OptionalConfigUtils; +import org.apache.rya.indexing.TemporalInstantRfc3339; +import org.apache.rya.indexing.accumulo.ConfigUtils; +import org.apache.rya.indexing.geotemporal.model.Event; +import org.apache.rya.indexing.geotemporal.mongo.MongoGeoTemporalIndexer; +import org.apache.rya.indexing.geotemporal.storage.EventStorage; +import org.apache.rya.mongodb.MockMongoFactory; +import org.apache.rya.mongodb.MongoDBRdfConfiguration; +import org.junit.Before; +import org.junit.Test; +import org.openrdf.model.URI; +import org.openrdf.model.Value; +import org.openrdf.model.ValueFactory; +import org.openrdf.model.impl.ValueFactoryImpl; +import org.openrdf.query.BindingSet; +import org.openrdf.query.QueryLanguage; +import org.openrdf.query.TupleQueryResult; +import org.openrdf.query.impl.MapBindingSet; +import org.openrdf.repository.sail.SailRepository; +import org.openrdf.repository.sail.SailRepositoryConnection; +import org.openrdf.sail.Sail; + +import com.mongodb.MongoClient; + +public class MongoGeoTemporalIndexIT { + private static final String URI_PROPERTY_AT_TIME = "Property:atTime"; + + private static final ValueFactory VF = ValueFactoryImpl.getInstance(); + private MongoDBRdfConfiguration conf; + private SailRepositoryConnection conn; + private MongoClient mongoClient; + + @Before + public void setUp() throws Exception{ + mongoClient = MockMongoFactory.newFactory().newMongoClient(); + conf = new MongoDBRdfConfiguration(); + conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "test"); + conf.set(MongoDBRdfConfiguration.MONGO_COLLECTION_PREFIX, "rya"); + conf.set(RdfCloudTripleStoreConfiguration.CONF_TBL_PREFIX, "rya"); + conf.setBoolean(ConfigUtils.USE_MONGO, true); + conf.setBoolean(OptionalConfigUtils.USE_GEOTEMPORAL, true); + conf.setMongoClient(mongoClient); + + final Sail sail = GeoRyaSailFactory.getInstance(conf); + conn = new SailRepository(sail).getConnection(); + conn.begin(); + + addStatements(); + } + + @Test + public void ensureInEventStore_Test() throws Exception { + final MongoGeoTemporalIndexer indexer = new MongoGeoTemporalIndexer(); + indexer.initIndexer(conf, mongoClient); + + final EventStorage events = indexer.getEventStorage(conf); + final RyaURI subject = new RyaURI("urn:event1"); + final Optional<Event> event = events.get(subject); + assertTrue(event.isPresent()); + } + + @Test + public void constantSubjQuery_Test() 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 * " + + "WHERE { " + + " <urn:event1> time:atTime ?time . " + + " <urn:event1> geo:asWKT ?point . " + + " FILTER(geof:sfWithin(?point, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(tempo:equals(?time, \"2015-12-30T12:00:00Z\")) " + + "}"; + + final TupleQueryResult rez = conn.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate(); + final Set<BindingSet> results = new HashSet<>(); + while(rez.hasNext()) { + final BindingSet bs = rez.next(); + results.add(bs); + } + final MapBindingSet expected = new MapBindingSet(); + expected.addBinding("point", VF.createLiteral("POINT (0 0)")); + expected.addBinding("time", VF.createLiteral("2015-12-30T12:00:00Z")); + + assertEquals(1, results.size()); + assertEquals(expected, results.iterator().next()); + } + + @Test + public void variableSubjQuery_Test() 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 * " + + "WHERE { " + + " ?subj time:atTime ?time . " + + " ?subj geo:asWKT ?point . " + + " FILTER(geof:sfWithin(?point, \"POLYGON((-3 -2, -3 2, 1 2, 1 -2, -3 -2))\"^^geo:wktLiteral)) " + + " FILTER(tempo:equals(?time, \"2015-12-30T12:00:00Z\")) " + + "}"; + + final TupleQueryResult rez = conn.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate(); + final List<BindingSet> results = new ArrayList<>(); + while(rez.hasNext()) { + final BindingSet bs = rez.next(); + results.add(bs); + } + final MapBindingSet expected1 = new MapBindingSet(); + expected1.addBinding("point", VF.createLiteral("POINT (0 0)")); + expected1.addBinding("time", VF.createLiteral("2015-12-30T12:00:00Z")); + + final MapBindingSet expected2 = new MapBindingSet(); + expected2.addBinding("point", VF.createLiteral("POINT (1 1)")); + expected2.addBinding("time", VF.createLiteral("2015-12-30T12:00:00Z")); + + assertEquals(2, results.size()); + assertEquals(expected1, results.get(0)); + assertEquals(expected2, results.get(1)); + } + + private void addStatements() throws Exception { + URI subject = VF.createURI("urn:event1"); + final URI predicate = VF.createURI(URI_PROPERTY_AT_TIME); + Value object = VF.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + conn.add(VF.createStatement(subject, predicate, object)); + + object = VF.createLiteral("Point(0 0)", GeoConstants.XMLSCHEMA_OGC_WKT); + conn.add(VF.createStatement(subject, GeoConstants.GEO_AS_WKT, object)); + + subject = VF.createURI("urn:event2"); + object = VF.createLiteral(new TemporalInstantRfc3339(2015, 12, 30, 12, 00, 0).toString()); + conn.add(VF.createStatement(subject, predicate, object)); + + object = VF.createLiteral("Point(1 1)", GeoConstants.XMLSCHEMA_OGC_WKT); + conn.add(VF.createStatement(subject, GeoConstants.GEO_AS_WKT, object)); + } +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java new file mode 100644 index 0000000..d9e0294 --- /dev/null +++ b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/model/EventQueryNodeTest.java @@ -0,0 +1,368 @@ +/** + * 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.GeoTemporalTestBase; +import org.apache.rya.indexing.geotemporal.mongo.MongoEventStorage; +import org.apache.rya.indexing.geotemporal.storage.EventStorage; +import org.apache.rya.mongodb.MockMongoFactory; +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.mongodb.MongoClient; +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 GeoTemporalTestBase { + 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 MongoClient client = MockMongoFactory.newFactory().newMongoClient(); + final EventStorage storage = new MongoEventStorage(client, "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 MongoClient client = MockMongoFactory.newFactory().newMongoClient(); + final EventStorage storage = new MongoEventStorage(client, "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 MongoClient client = MockMongoFactory.newFactory().newMongoClient(); + final EventStorage storage = new MongoEventStorage(client, "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 MongoClient client = MockMongoFactory.newFactory().newMongoClient(); + final EventStorage storage = new MongoEventStorage(client, "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/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/EventDocumentConverterTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/EventDocumentConverterTest.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/EventDocumentConverterTest.java new file mode 100644 index 0000000..3f2f9d5 --- /dev/null +++ b/extras/rya.geoindexing/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/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java new file mode 100644 index 0000000..edce1ec --- /dev/null +++ b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/GeoTemporalMongoDBStorageStrategyTest.java @@ -0,0 +1,469 @@ +/* +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; +import org.apache.rya.indexing.geotemporal.GeoTemporalTestBase; +import org.apache.rya.indexing.geotemporal.GeoTemporalIndexer.GeoPolicy; +import org.apache.rya.indexing.geotemporal.GeoTemporalIndexer.TemporalPolicy; +import org.apache.rya.indexing.geotemporal.mongo.GeoTemporalMongoDBStorageStrategy; +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\" : {" + + "\"$polygon\" : [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]" + + "}" + + "}" + + "}"; + 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\" : [ [ -4.0 , -3.0] , [ -4.0 , 3.0] , [ 2.0 , 3.0] , [ 2.0 , -3.0] , [ -4.0 , -3.0]]" + + "}, {" + + "\"location\" : {" + + "\"$geoIntersects\" : {" + + "\"$polygon\" : [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]" + + "}" + + "}" + + "}]" + + "}"; + 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\" : {" + + "\"$polygon\" : [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]" + + "}," + + "}}, {" + + "\"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\" : [ [ -4.0 , -3.0] , [ -4.0 , 3.0] , [ 2.0 , 3.0] , [ 2.0 , -3.0] , [ -4.0 , -3.0]]" + + "}, {" + + "\"location\" : {" + + "\"$geoWithin\" : {" + + "\"$polygon\" : [ [ -3.0 , -2.0] , [ -3.0 , 2.0] , [ 1.0 , 2.0] , [ 1.0 , -2.0] , [ -3.0 , -2.0]]" + + "}" + + "}" + + "}]" + + "},{" + + "\"$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\" : [ [ -4.0 , -3.0] , [ -4.0 , 3.0] , [ 2.0 , 3.0] , [ 2.0 , -3.0] , [ -4.0 , -3.0]]" + + "},{" + + "\"$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 : [ [ -77.03524 , 38.889468]]" + + "}"; + 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/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoEventStorageTest.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoEventStorageTest.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoEventStorageTest.java new file mode 100644 index 0000000..5b07460 --- /dev/null +++ b/extras/rya.geoindexing/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/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java new file mode 100644 index 0000000..802e8c1 --- /dev/null +++ b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoGeoTemporalIndexerIT.java @@ -0,0 +1,126 @@ +/** + * 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.RdfCloudTripleStoreConfiguration; +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.mongo.MongoGeoTemporalIndexer; +import org.apache.rya.indexing.geotemporal.storage.EventStorage; +import org.apache.rya.mongodb.MockMongoFactory; +import org.apache.rya.mongodb.MongoDBRdfConfiguration; +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.mongodb.MongoClient; +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 { + final MongoClient client = MockMongoFactory.newFactory().newMongoClient(); + indexer = new MongoGeoTemporalIndexer(); + conf.setMongoDBName("GEO_TEMPORAL_INDEXER_TEST"); + conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "GEO_TEMPORAL_INDEXER_TEST"); + conf.setMongoClient(client); + conf.set(RdfCloudTripleStoreConfiguration.CONF_TBL_PREFIX, "rya_"); + 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/646d21b4/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java ---------------------------------------------------------------------- diff --git a/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java new file mode 100644 index 0000000..bd7b5db --- /dev/null +++ b/extras/rya.geoindexing/src/test/java/org/apache/rya/indexing/geotemporal/mongo/MongoITBase.java @@ -0,0 +1,81 @@ +/** + * 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.HashSet; +import java.util.Set; + +import org.apache.hadoop.conf.Configuration; +import org.apache.rya.indexing.geotemporal.GeoTemporalTestBase; +import org.apache.rya.mongodb.MockMongoFactory; +import org.apache.rya.mongodb.MongoConnectorFactory; +import org.apache.rya.mongodb.MongoDBRdfConfiguration; +import org.junit.After; +import org.junit.AfterClass; +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 { + protected final MongoDBRdfConfiguration conf = new MongoDBRdfConfiguration( new Configuration() ); + + private MongoClient mongoClient = null; + private Set<String> originalDbNames = null; + + @Before + public void setupTest() throws Exception { + conf.setMongoDBName("testDB"); + conf.setMongoInstance("testDB"); + conf.setMongoPort("27017"); + + mongoClient = MockMongoFactory.newFactory().newMongoClient(); + conf.setMongoClient(mongoClient);; + // Store the names of the DBs that are present before running the test. + originalDbNames = new HashSet<>(); + for(final String name : mongoClient.listDatabaseNames()) { + originalDbNames.add(name); + } + } + + @After + public void cleanupTest() { + // Remove any DBs that were created by the test. + for(final String dbName : mongoClient.listDatabaseNames()) { + if(!originalDbNames.contains(dbName)) { + mongoClient.dropDatabase(dbName); + } + } + } + + @AfterClass + public static void shutdown() { + MongoConnectorFactory.closeMongoClient(); + } + + /** + * @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
