Repository: marmotta Updated Branches: refs/heads/develop 1ee825c47 -> 3493fe73b
add some SPARQL 1.1 compliance tests Project: http://git-wip-us.apache.org/repos/asf/marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/marmotta/commit/3493fe73 Tree: http://git-wip-us.apache.org/repos/asf/marmotta/tree/3493fe73 Diff: http://git-wip-us.apache.org/repos/asf/marmotta/diff/3493fe73 Branch: refs/heads/develop Commit: 3493fe73b68dfd6ffd017d9a53d36cbcb7686b1f Parents: 1ee825c Author: Sebastian Schaffert <[email protected]> Authored: Tue Nov 11 10:26:31 2014 +0100 Committer: Sebastian Schaffert <[email protected]> Committed: Tue Nov 11 10:26:31 2014 +0100 ---------------------------------------------------------------------- .../testsuite/KiWiSparqlComplianceTest.java | 338 +++++++++++++++++++ .../kiwi/sparql/testsuite/date-num-str.ttl | 24 ++ .../marmotta/kiwi/sparql/testsuite/hours.sparql | 4 + .../kiwi/sparql/testsuite/minutes.sparql | 4 + .../marmotta/kiwi/sparql/testsuite/month.sparql | 4 + .../kiwi/sparql/testsuite/seconds.sparql | 4 + .../marmotta/kiwi/sparql/testsuite/year.sparql | 4 + .../marmotta/kiwi/persistence/h2/H2Dialect.java | 2 +- .../kiwi/persistence/mysql/MySQLDialect.java | 2 +- 9 files changed, 384 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/testsuite/KiWiSparqlComplianceTest.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/testsuite/KiWiSparqlComplianceTest.java b/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/testsuite/KiWiSparqlComplianceTest.java new file mode 100644 index 0000000..1938b29 --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/java/org/apache/marmotta/kiwi/sparql/testsuite/KiWiSparqlComplianceTest.java @@ -0,0 +1,338 @@ +/* + * 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.marmotta.kiwi.sparql.testsuite; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import com.google.common.collect.Lists; +import info.aduna.iteration.Iterations; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.IOUtils; +import org.apache.marmotta.commons.sesame.model.StatementCommons; +import org.apache.marmotta.kiwi.config.KiWiConfiguration; +import org.apache.marmotta.kiwi.sail.KiWiStore; +import org.apache.marmotta.kiwi.sparql.sail.KiWiSparqlSail; +import org.apache.marmotta.kiwi.test.junit.KiWiDatabaseRunner; +import org.junit.*; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; +import org.junit.runner.RunWith; +import org.openrdf.model.BNode; +import org.openrdf.model.Statement; +import org.openrdf.model.URI; +import org.openrdf.model.impl.URIImpl; +import org.openrdf.query.*; +import org.openrdf.query.impl.DatasetImpl; +import org.openrdf.repository.Repository; +import org.openrdf.repository.RepositoryConnection; +import org.openrdf.repository.RepositoryException; +import org.openrdf.repository.sail.SailRepository; +import org.openrdf.rio.RDFFormat; +import org.openrdf.rio.RDFParseException; +import org.openrdf.sail.memory.MemoryStore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * A collection of tests from the SPARQL 1.1 testsuite, for testing compliance. + * + * @author Sebastian Schaffert ([email protected]) + */ +@RunWith(KiWiDatabaseRunner.class) +public class KiWiSparqlComplianceTest { + + + private KiWiStore store; + + private KiWiSparqlSail ssail; + + private Repository repository; + + // reference repository for checking if the results are the same + private Repository reference; + + private final KiWiConfiguration dbConfig; + + public KiWiSparqlComplianceTest(KiWiConfiguration dbConfig) { + this.dbConfig = dbConfig; + dbConfig.setFulltextEnabled(true); + dbConfig.setFulltextLanguages(new String[] {"en"}); + } + + + @Before + public void initDatabase() throws RepositoryException, IOException, RDFParseException { + store = new KiWiStore(dbConfig); + ssail = new KiWiSparqlSail(store); + repository = new SailRepository(ssail); + repository.initialize(); + + // load demo data + RepositoryConnection con = repository.getConnection(); + try { + con.begin(); + + con.add(this.getClass().getResourceAsStream("date-num-str.ttl"), "http://localhost/test/", RDFFormat.TURTLE); + + con.commit(); + } finally { + con.close(); + } + + reference = new SailRepository(new MemoryStore()); + reference.initialize(); + + // load demo data + RepositoryConnection con2 = reference.getConnection(); + try { + con2.begin(); + + con2.add(this.getClass().getResourceAsStream("date-num-str.ttl"), "http://localhost/test/", RDFFormat.TURTLE); + + con2.commit(); + } finally { + con2.close(); + } + } + + @After + public void dropDatabase() throws RepositoryException, SQLException { + store.getPersistence().dropDatabase(); + repository.shutDown(); + } + + final Logger logger = + LoggerFactory.getLogger(this.getClass()); + + @Rule + public TestWatcher watchman = new TestWatcher() { + /** + * Invoked when a test is about to start + */ + @Override + protected void starting(Description description) { + logger.info("{} being run...", description.getMethodName()); + } + }; + + + @Test + public void testQueryHours() throws Exception { + testQuery("hours.sparql"); + } + + @Test + public void testQueryMinutes() throws Exception { + testQuery("minutes.sparql"); + } + + @Test + public void testQuerySeconds() throws Exception { + testQuery("seconds.sparql"); + } + + @Test + public void testQueryMonth() throws Exception { + testQuery("month.sparql"); + } + + @Test + public void testQueryYear() throws Exception { + testQuery("year.sparql"); + } + + + private void testQuery(String filename) throws Exception { + String queryString = IOUtils.toString(this.getClass().getResourceAsStream(filename), "UTF-8"); + + RepositoryConnection con1 = repository.getConnection(); + RepositoryConnection con2 = reference.getConnection(); + try { + con2.begin(); + + TupleQuery query2 = con2.prepareTupleQuery(QueryLanguage.SPARQL, queryString); + TupleQueryResult result2 = query2.evaluate(); + + con2.commit(); + + Assume.assumeTrue(result2.hasNext()); + + con1.begin(); + + TupleQuery query1 = con1.prepareTupleQuery(QueryLanguage.SPARQL, queryString); + TupleQueryResult result1 = query1.evaluate(); + + con1.commit(); + + Assert.assertTrue(result1.hasNext()); + + + compareResults(result1, result2); + + } catch(RepositoryException ex) { + con1.rollback(); + } finally { + con1.close(); + con2.close(); + } + } + + private void testUpdate(String filename, URI... properties) throws Exception { + String queryString = IOUtils.toString(this.getClass().getResourceAsStream(filename), "UTF-8"); + + RepositoryConnection con1 = repository.getConnection(); + RepositoryConnection con2 = reference.getConnection(); + try { + con2.begin(); + + Update query2 = con2.prepareUpdate(QueryLanguage.SPARQL, queryString); + query2.execute(); + + con2.commit(); + + con1.begin(); + + Update query1 = con1.prepareUpdate(QueryLanguage.SPARQL, queryString); + // workaround for a Sesame bug: we explicitly set the context for the query in the dataset + + URI context = new URIImpl("http://localhost/mycontext"); + DatasetImpl ds = new DatasetImpl(); + //ds.addDefaultGraph(context); + //ds.addNamedGraph(context); + //ds.addDefaultRemoveGraph(context); + ds.setDefaultInsertGraph(context); + query1.setDataset(ds); + + query1.execute(); + + con1.commit(); + + + con1.begin(); + Set<Statement> set1 = new HashSet<>(); + for(URI u : properties) { + set1.addAll(Collections2.transform(Iterations.asSet(con1.getStatements(null, u, null, true)), new StatementCommons.TripleEquality())); + } + con1.commit(); + + con2.begin(); + Set<Statement> set2 = new HashSet<>(); + for(URI u : properties) { + set2.addAll(Collections2.transform(Iterations.asSet(con2.getStatements(null,u,null,true)), new StatementCommons.TripleEquality())); + } + con2.commit(); + + for(Statement stmt : set1) { + Assert.assertTrue(stmt + " not contained in set 2", set2.contains(stmt)); + } + for(Statement stmt : set2) { + Assert.assertTrue(stmt + " not contained in set 1", set1.contains(stmt)); + } + + } catch(RepositoryException ex) { + con1.rollback(); + } finally { + con1.close(); + con2.close(); + } + } + + + private void compareResults(TupleQueryResult result1, TupleQueryResult result2) throws QueryEvaluationException { + List<BindingSet> bindingSets1 = Iterations.asList(result1); + List<BindingSet> bindingSets2 = Iterations.asList(result2); + + Set<Set<Pair>> set1 = new HashSet<Set<Pair>>(Lists.transform(bindingSets1,new BindingSetPairFunction())); + Set<Set<Pair>> set2 = new HashSet<Set<Pair>>(Lists.transform(bindingSets2,new BindingSetPairFunction())); + + for(Set<Pair> p : set1) { + Assert.assertTrue("binding " + p + " from result set not found in reference set", set2.contains(p)); + } + for(Set<Pair> p : set2) { + Assert.assertTrue("binding " + p + " from reference set not found in result set", set1.contains(p)); + } + + + Assert.assertTrue(CollectionUtils.isEqualCollection(set1, set2)); + } + + + private static class BindingSetPairFunction implements Function<BindingSet, Set<Pair>> { + @Override + public Set<Pair> apply(BindingSet input) { + Set<Pair> result = new HashSet<Pair>(); + + for(Binding b : input) { + Pair p = new Pair(b.getName(), b.getValue() != null ? (b.getValue() instanceof BNode ? "_" : b.getValue().stringValue()) : null); + result.add(p); + } + + return result; + } + } + + private static class Pair { + String key, value; + + private Pair(String key, String value) { + this.key = key; + this.value = value; + } + + private String getKey() { + return key; + } + + private String getValue() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Pair pair = (Pair) o; + + if (!key.equals(pair.getKey())) return false; + if (value != null ? !value.equals(pair.getValue()) : pair.getValue() != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = key.hashCode(); + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return key + " = " + value; + } + } + + +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/date-num-str.ttl ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/date-num-str.ttl b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/date-num-str.ttl new file mode 100644 index 0000000..a078c84 --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/date-num-str.ttl @@ -0,0 +1,24 @@ +@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . +@prefix : <http://example.org/> . + +# numeric data +:n4 :num -2 . +:n1 :num -1 . +:n2 :num -1.6 . +:n3 :num 1.1 . +:n5 :num 2.5 . + +# string data +:s1 :str "foo" . +:s2 :str "bar"@en . +:s3 :str "BAZ" . +:s4 :str "é£ã¹ç©" . +:s5 :str "100%" . +:s6 :str "abc"^^xsd:string . +:s7 :str "DEF"^^xsd:string . + +# date data +:d1 :date "2010-06-21T11:28:01Z"^^xsd:dateTime . +:d2 :date "2010-12-21T15:38:02-08:00"^^xsd:dateTime . +:d3 :date "2008-06-20T23:59:00Z"^^xsd:dateTime . +:d4 :date "2011-02-01T01:02:03"^^xsd:dateTime . http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/hours.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/hours.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/hours.sparql new file mode 100644 index 0000000..837c871 --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/hours.sparql @@ -0,0 +1,4 @@ +PREFIX : <http://example.org/> +SELECT ?s (HOURS(?date) AS ?x) WHERE { + ?s :date ?date +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/minutes.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/minutes.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/minutes.sparql new file mode 100644 index 0000000..982bef3 --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/minutes.sparql @@ -0,0 +1,4 @@ +PREFIX : <http://example.org/> +SELECT ?s (MINUTES(?date) AS ?x) WHERE { + ?s :date ?date +} http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/month.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/month.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/month.sparql new file mode 100644 index 0000000..1bba80a --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/month.sparql @@ -0,0 +1,4 @@ +PREFIX : <http://example.org/> +SELECT ?s (MONTH(?date) AS ?x) WHERE { + ?s :date ?date +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/seconds.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/seconds.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/seconds.sparql new file mode 100644 index 0000000..cfe4d5d --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/seconds.sparql @@ -0,0 +1,4 @@ +PREFIX : <http://example.org/> +SELECT ?s (SECONDS(?date) AS ?x) WHERE { + ?s :date ?date +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/year.sparql ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/year.sparql b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/year.sparql new file mode 100644 index 0000000..1f0da4b --- /dev/null +++ b/libraries/kiwi/kiwi-sparql/src/test/resources/org/apache/marmotta/kiwi/sparql/testsuite/year.sparql @@ -0,0 +1,4 @@ +PREFIX : <http://example.org/> +SELECT ?s (YEAR(?date) AS ?x) WHERE { + ?s :date ?date +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java index 7ed0b09..c73deb9 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/h2/H2Dialect.java @@ -114,7 +114,7 @@ public class H2Dialect extends KiWiDialect { */ @Override public String getDateTimeTZ(String alias) { - return String.format("DATEADD('SECOND', %s.tzoffset, %s.tvalue)"); + return String.format("DATEADD('SECOND', %s.tzoffset, %s.tvalue)", alias, alias); } http://git-wip-us.apache.org/repos/asf/marmotta/blob/3493fe73/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java ---------------------------------------------------------------------- diff --git a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java index c8c4e50..d390da8 100644 --- a/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java +++ b/libraries/kiwi/kiwi-triplestore/src/main/java/org/apache/marmotta/kiwi/persistence/mysql/MySQLDialect.java @@ -128,7 +128,7 @@ public class MySQLDialect extends KiWiDialect { */ @Override public String getDateTimeTZ(String alias) { - return String.format("DATE_ADD(%s.tvalue, INTERVAL %s.tzoffset SECOND)"); + return String.format("DATE_ADD(%s.tvalue, INTERVAL %s.tzoffset SECOND)", alias, alias); } /**
