Repository: incubator-rya Updated Branches: refs/heads/master 4ac4e8674 -> 529f2d595
http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c4d4bfe7/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java new file mode 100644 index 0000000..4ddb2a5 --- /dev/null +++ b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexIT.java @@ -0,0 +1,326 @@ +/** + * 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.mongo; + +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.accumulo.ConfigUtils; +import org.apache.rya.indexing.entity.model.Entity; +import org.apache.rya.indexing.entity.model.Type; +import org.apache.rya.indexing.entity.storage.EntityStorage; +import org.apache.rya.indexing.entity.storage.TypeStorage; +import org.apache.rya.indexing.entity.update.mongo.MongoEntityIndexer; +import org.apache.rya.mongodb.MockMongoFactory; +import org.apache.rya.mongodb.MongoDBRdfConfiguration; +import org.apache.rya.sail.config.RyaSailFactory; +import org.bson.Document; +import org.junit.Before; +import org.junit.Test; +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.ValueFactoryImpl; +import org.openrdf.model.vocabulary.RDF; +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.google.common.collect.ImmutableSet; +import com.mongodb.Block; +import com.mongodb.MongoClient; +import com.mongodb.client.MongoDatabase; + +import de.flapdoodle.embed.mongo.distribution.Version; + +public class MongoEntityIndexIT { + private static final ValueFactory VF = ValueFactoryImpl.getInstance(); + private MongoDBRdfConfiguration conf; + private SailRepositoryConnection conn; + private MongoEntityIndexer indexer; + private MongoClient mongoClient; + + @Before + public void setUp() throws Exception{ + mongoClient = MockMongoFactory.with(Version.Main.PRODUCTION).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.setMongoClient(mongoClient); + conf.setBoolean(ConfigUtils.USE_ENTITY, true); + final int port = mongoClient.getServerAddressList().get(0).getPort(); + conf.set(MongoDBRdfConfiguration.MONGO_INSTANCE_PORT, Integer.toString(port)); + + final Sail sail = RyaSailFactory.getInstance(conf); + conn = new SailRepository(sail).getConnection(); + conn.begin(); + + indexer = new MongoEntityIndexer(); + indexer.setConf(conf); + indexer.init(); + } + + @Test + public void ensureInEntityStore_Test() throws Exception { + setupTypes(); + addStatements(); + + final MongoDatabase db = mongoClient.getDatabase("test"); + db.listCollections().forEach((Block<Document>)doc -> { + System.out.println(doc); + }); + + + final EntityStorage entities = indexer.getEntityStorage(conf); + final RyaURI subject = new RyaURI("urn:alice"); + final Optional<Entity> alice = entities.get(subject); + assertTrue(alice.isPresent()); + } + + @Test + public void sparqlQuery_Test() throws Exception { + setupTypes(); + addStatements(); + //conn.commit(); + + final String query = "SELECT * WHERE { " + + "<urn:strawberry> <" + RDF.TYPE + "> <urn:icecream> ."+ + "<urn:strawberry> <urn:brand> ?brand . " + + "<urn:strawberry> <urn:flavor> ?flavor . " + + "}"; + + final TupleQueryResult rez = conn.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate(); + final Set<BindingSet> results = new HashSet<>(); + while(rez.hasNext()) { + final BindingSet bs = rez.next(); + System.out.println(bs); + results.add(bs); + } + final MapBindingSet expected = new MapBindingSet(); + expected.addBinding("flavor", ValueFactoryImpl.getInstance().createLiteral("Strawberry")); + expected.addBinding("brand", ValueFactoryImpl.getInstance().createLiteral("Awesome Icecream")); + + assertEquals(1, results.size()); + assertEquals(expected, results.iterator().next()); + } + + @Test + public void partialQuery_Test() throws Exception { + setupTypes(); + addStatements(); + conn.commit(); + + final String query = "SELECT * WHERE { " + + "<urn:george> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:george> <urn:name> ?name . " + + "<urn:george> <urn:eye> ?eye . " + + "}"; + + final TupleQueryResult rez = conn.prepareTupleQuery(QueryLanguage.SPARQL, query).evaluate(); + final Set<BindingSet> results = new HashSet<>(); + while(rez.hasNext()) { + final BindingSet bs = rez.next(); + System.out.println(bs); + results.add(bs); + } + final ValueFactory vf = ValueFactoryImpl.getInstance(); + final MapBindingSet expected = new MapBindingSet(); + //expected.addBinding("name", vf.createURI("http://www.w3.org/2001/SMLSchema#string", "George")); + expected.addBinding("name", vf.createLiteral("George")); + expected.addBinding("eye", vf.createLiteral("blue")); + + assertEquals(1, results.size()); + assertEquals(expected, results.iterator().next()); + } + + private void setupTypes() throws Exception { + final TypeStorage typeStore = indexer.getTypeStorage(conf); + // Add some Types to the storage. + final Type cat = new Type(new RyaURI("urn:cat"), + ImmutableSet.<RyaURI>builder() + .add(new RyaURI("urn:numLegs")) + .add(new RyaURI("urn:eye")) + .add(new RyaURI("urn:species")) + .build()); + + final Type dog = new Type(new RyaURI("urn:dog"), + ImmutableSet.<RyaURI>builder() + .add(new RyaURI("urn:numLegs")) + .add(new RyaURI("urn:eye")) + .add(new RyaURI("urn:species")) + .build()); + + final Type icecream = new Type(new RyaURI("urn:icecream"), + ImmutableSet.<RyaURI>builder() + .add(new RyaURI("urn:brand")) + .add(new RyaURI("urn:flavor")) + .add(new RyaURI("urn:cost")) + .build()); + + final Type person = new Type(new RyaURI("urn:person"), + ImmutableSet.<RyaURI>builder() + .add(new RyaURI("urn:name")) + .add(new RyaURI("urn:age")) + .add(new RyaURI("urn:eye")) + .build()); + + typeStore.create(cat); + typeStore.create(dog); + typeStore.create(icecream); + typeStore.create(person); + } + + private void addStatements() throws Exception { + final List<Statement> stmnts = new ArrayList<>(); + + //alice + URI subject = VF.createURI("urn:alice"); + URI predicate = VF.createURI("urn:name"); + Value object = VF.createLiteral("Alice"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:eye"); + object = VF.createLiteral("blue"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:age"); + object = VF.createLiteral(30); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:person"))); + + //bob + subject = VF.createURI("urn:bob"); + predicate = VF.createURI("urn:name"); + object = VF.createLiteral("Bob"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:eye"); + object = VF.createLiteral("brown"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:age"); + object = VF.createLiteral(57); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:person"))); + + //charlie + subject = VF.createURI("urn:charlie"); + predicate = VF.createURI("urn:name"); + object = VF.createLiteral("Charlie"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:eye"); + object = VF.createLiteral("hazel"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:age"); + object = VF.createLiteral(25); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:person"))); + + //david + subject = VF.createURI("urn:david"); + predicate = VF.createURI("urn:name"); + object = VF.createLiteral("David"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:eye"); + object = VF.createLiteral("brown"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:age"); + object = VF.createLiteral(30); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:person"))); + + //eve + subject = VF.createURI("urn:eve"); + predicate = VF.createURI("urn:name"); + object = VF.createLiteral("Bob"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:age"); + object = VF.createLiteral(25); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:person"))); + + //frank + subject = VF.createURI("urn:frank"); + predicate = VF.createURI("urn:name"); + object = VF.createLiteral("Frank"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:eye"); + object = VF.createLiteral("Hazel"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:age"); + object = VF.createLiteral(57); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:person"))); + + //george + subject = VF.createURI("urn:george"); + predicate = VF.createURI("urn:name"); + object = VF.createLiteral("George"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:eye"); + object = VF.createLiteral("blue"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:age"); + object = VF.createLiteral(30); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:person"))); + + // Some Icecream typed objects. + //chocolate + subject = VF.createURI("urn:chocolate"); + predicate = VF.createURI("urn:brand"); + object = VF.createLiteral("Awesome Icecream"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:flavor"); + object = VF.createLiteral("Chocolate"); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:icecream"))); + + //vanilla + subject = VF.createURI("urn:vanilla"); + predicate = VF.createURI("urn:brand"); + object = VF.createLiteral("Awesome Icecream"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:flavor"); + object = VF.createLiteral("Vanilla"); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:icecream"))); + + //strawberry + subject = VF.createURI("urn:strawberry"); + predicate = VF.createURI("urn:brand"); + object = VF.createLiteral("Awesome Icecream"); + conn.add(VF.createStatement(subject, predicate, object)); + predicate = VF.createURI("urn:flavor"); + object = VF.createLiteral("Strawberry"); + conn.add(VF.createStatement(subject, predicate, object)); + conn.add(VF.createStatement(subject, RDF.TYPE, VF.createURI("urn:icecream"))); + } +} http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/c4d4bfe7/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java ---------------------------------------------------------------------- diff --git a/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java new file mode 100644 index 0000000..f4aeaa1 --- /dev/null +++ b/extras/indexing/src/test/java/org/apache/rya/indexing/mongo/MongoEntityIndexTest.java @@ -0,0 +1,260 @@ +/** + * 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.mongo; + +import java.util.List; + +import org.apache.rya.api.domain.RyaType; +import org.apache.rya.api.domain.RyaURI; +import org.apache.rya.indexing.accumulo.ConfigUtils; +import org.apache.rya.indexing.entity.EntityIndexOptimizer; +import org.apache.rya.indexing.entity.model.Entity; +import org.apache.rya.indexing.entity.model.Property; +import org.apache.rya.indexing.entity.model.Type; +import org.apache.rya.indexing.entity.query.EntityQueryNode; +import org.apache.rya.indexing.entity.storage.EntityStorage; +import org.apache.rya.indexing.entity.storage.TypeStorage; +import org.apache.rya.mongodb.MockMongoFactory; +import org.apache.rya.mongodb.MongoDBRdfConfiguration; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.openrdf.model.vocabulary.RDF; +import org.openrdf.query.MalformedQueryException; +import org.openrdf.query.algebra.QueryModelNode; +import org.openrdf.query.algebra.StatementPattern; +import org.openrdf.query.algebra.TupleExpr; +import org.openrdf.query.algebra.helpers.QueryModelVisitorBase; +import org.openrdf.query.algebra.helpers.StatementPatternCollector; +import org.openrdf.query.parser.sparql.SPARQLParser; + +import com.google.common.collect.ImmutableSet; +import com.mongodb.MongoClient; + +public class MongoEntityIndexTest { + private static final Type PERSON_TYPE = + new Type(new RyaURI("urn:person"), + ImmutableSet.<RyaURI>builder() + .add(new RyaURI("urn:name")) + .add(new RyaURI("urn:age")) + .add(new RyaURI("urn:eye")) + .build()); + private static final RyaURI RYA_PERSON_TYPE = new RyaURI("urn:person"); + + static MongoDBRdfConfiguration conf; + private static EntityIndexOptimizer optimizer; + private static EntityStorage entityStorage; + + @BeforeClass + public static void beforeClass() throws Exception { + conf = new MongoDBRdfConfiguration(); + conf.set(ConfigUtils.USE_MONGO, "true"); + conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "test"); + conf.set(MongoDBRdfConfiguration.MONGO_COLLECTION_PREFIX, "rya_"); + conf.setTablePrefix("another_"); + + final MongoClient client = MockMongoFactory.newFactory().newMongoClient(); + conf.setMongoClient(client); + + optimizer = new EntityIndexOptimizer(); + optimizer.setConf(conf); + + final TypeStorage typeStorage = optimizer.getTypeStorage(); + typeStorage.create(PERSON_TYPE); + + final Entity entity = Entity.builder() + .setSubject(new RyaURI("urn:SSN:111-11-1111")) + .setExplicitType(RYA_PERSON_TYPE) + .setProperty(RYA_PERSON_TYPE, new Property(new RyaURI("urn:age"), new RyaType("25"))) + .setProperty(RYA_PERSON_TYPE, new Property(new RyaURI("urn:eye"), new RyaType("blue"))) + .setProperty(RYA_PERSON_TYPE, new Property(new RyaURI("urn:name"), new RyaType("bob"))) + .build(); + entityStorage = optimizer.getEntityStorage(); + entityStorage.create(entity); + } + + @Test() + public void queryIsFullEntity() throws Exception { + // A pattern that has two different subjects. + final String query = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:name> ?name . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + "}"; + + final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(query), entityStorage); + assertOptimizer(query, expected); + } + + @Test() + public void queryIsPartEntity() throws Exception { + // A pattern that has two different subjects. + final String query = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "}"; + + final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(query), entityStorage); + assertOptimizer(query, expected); + } + + @Test() + public void queryIsPartEntityandExtra() throws Exception { + // A pattern that has two different subjects. + final String query = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:222-22-2222> <urn:age> ?age . " + + "<urn:SSN:222-22-2222> <urn:eye> ?eye . " + + "<urn:SSN:222-22-2222> <urn:name> ?name . " + + "}"; + + final String expectedQuery = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "}"; + + final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage); + assertOptimizer(query, expected); + } + + @Test() + public void queryIsFullEntityWithExtra() throws Exception { + // A pattern that has two different subjects. + final String query = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + "<urn:SSN:111-11-1111> <urn:name> ?name . " + + "<urn:SSN:222-22-2222> <urn:age> ?age . " + + "<urn:SSN:222-22-2222> <urn:eye> ?eye . " + + "<urn:SSN:222-22-2222> <urn:name> ?name . " + + "}"; + + final String expectedQuery = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + "<urn:SSN:111-11-1111> <urn:name> ?name . " + + "}"; + + final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage); + assertOptimizer(query, expected); + } + + @Test() + public void queryIsFullEntityWithOptional() throws Exception { + // A pattern that has two different subjects. + final String query = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + "<urn:SSN:111-11-1111> <urn:name> ?name . " + + " OPTIONAL{" + + " <urn:SSN:222-22-2222> <urn:age> ?age . " + + " <urn:SSN:222-22-2222> <urn:eye> ?eye . " + + " <urn:SSN:222-22-2222> <urn:name> ?name . " + + " } . " + + "}"; + + final String expectedQuery = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + "<urn:SSN:111-11-1111> <urn:name> ?name . " + + "}"; + + final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage); + assertOptimizer(query, expected); + } + + @Test() + public void queryIsSplitEntityWithOptional() throws Exception { + // A pattern that has two different subjects. + final String query = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + " OPTIONAL{" + + " <urn:SSN:111-11-1111> <urn:name> ?name . " + + " } . " + + "}"; + + final String expectedQuery = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + "}"; + + final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage); + assertOptimizer(query, expected); + } + + @Test() + public void queryEntityInOptional() throws Exception { + // A pattern that has two different subjects. + final String query = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <urn:age> ?age . " + + "<urn:SSN:111-11-1111> <urn:eye> ?eye . " + + " OPTIONAL{" + + " <urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + " <urn:SSN:111-11-1111> <urn:name> ?name . " + + " } . " + + "}"; + + final String expectedQuery = "SELECT * WHERE { " + + "<urn:SSN:111-11-1111> <" + RDF.TYPE + "> <urn:person> ."+ + "<urn:SSN:111-11-1111> <urn:name> ?name . " + + "}"; + + final EntityQueryNode expected = new EntityQueryNode(PERSON_TYPE, getSPs(expectedQuery), entityStorage); + assertOptimizer(query, expected); + } + + private static List<StatementPattern> getSPs(final String sparql) throws MalformedQueryException { + final StatementPatternCollector spCollector = new StatementPatternCollector(); + new SPARQLParser().parseQuery(sparql, null).getTupleExpr().visit(spCollector); + return spCollector.getStatementPatterns(); + } + + private void assertOptimizer(final String query, final EntityQueryNode expected) throws Exception { + final SPARQLParser parser = new SPARQLParser(); + final TupleExpr expr = parser.parseQuery(query, null).getTupleExpr(); + + optimizer.optimize(expr, null, null); + expr.visit(new EntityFetchingAsserterVisitor(expected)); + } + + private class EntityFetchingAsserterVisitor extends QueryModelVisitorBase<Exception> { + private final EntityQueryNode expected; + public EntityFetchingAsserterVisitor(final EntityQueryNode expected) { + this.expected = expected; + } + @Override + protected void meetNode(final QueryModelNode node) throws Exception { + if(node instanceof EntityQueryNode) { + Assert.assertEquals(expected, node); + } else { + super.meetNode(node); + } + } + } +} +
