/* * Licensed to Aduna under one or more contributor license agreements. * See the NOTICE.txt file distributed with this work for additional * information regarding copyright ownership. * * Aduna licenses this file to you under the terms of the Aduna BSD * License (the "License"); you may not use this file except in compliance * with the License. See the LICENSE.txt file distributed with this work * for the full License. * * 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.openrdf.query.parser.sparql.manifest; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.URL; import java.util.jar.JarFile; import junit.framework.TestResult; import junit.framework.TestSuite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import info.aduna.io.FileUtil; import info.aduna.io.ZipUtil; import org.openrdf.OpenRDFUtil; import org.openrdf.model.Resource; import org.openrdf.model.ValueFactory; import org.openrdf.query.BindingSet; import org.openrdf.query.QueryLanguage; import org.openrdf.query.TupleQueryResult; import org.openrdf.repository.Repository; import org.openrdf.repository.RepositoryConnection; import org.openrdf.repository.RepositoryException; import org.openrdf.repository.sail.SailRepository; import org.openrdf.repository.util.RDFInserter; import org.openrdf.rio.RDFHandlerException; import org.openrdf.rio.RDFParseException; import org.openrdf.rio.RDFParser; import org.openrdf.rio.turtle.TurtleParser; import org.openrdf.sail.memory.MemoryStore; /** * Functionality for creating a JUnit test suite out of a W3C Working * Group-style manifest for SPARQL query and update tests. * * @author Jeen Broekstra */ public class SPARQL11ManifestTest { static final Logger logger = LoggerFactory.getLogger(SPARQL11ManifestTest.class); private static File tmpDir; /** * Creates a new {@link TestSuite} for executiong of {@link SPARQLQueryTest} * s. * * @param factory * a factory class that creates each individual test case. * @param officialWorkingGroupTests * indicates whether to use the official W3C working group tests, or * Sesame's own set of tests. * @param approvedTestsOnly * if <code>true</code>, use working group-approved tests only. Has no * influence when officialWorkingGroup tests is set to * <code>false</code>. * @param useRemoteTests * if set to <code>true</code>, use manifests and tests located at * <code>http://www.w3.org/2009/sparql/docs/tests/data-sparql11/</code> * , instead of local copies. * @param excludedSubdirs * an (optionally empty) list of subdirectories to exclude from * testing. If specified, test cases in one of the supplied subdirs * will not be executed. If left empty, all tests will be executed. * @return a TestSuite. * @throws Exception */ public static TestSuite suite(SPARQLQueryTest.Factory factory, boolean officialWorkingGroupTests, boolean approvedTestsOnly, boolean useRemoteTests, String... excludedSubdirs) throws Exception { final String manifestFile = getManifestFile(officialWorkingGroupTests, useRemoteTests); System.err.println(manifestFile); TestSuite suite = new TestSuite(factory.getClass().getName()) { @Override public void run(TestResult result) { try { super.run(result); } finally { if (tmpDir != null) { try { FileUtil.deleteDir(tmpDir); } catch (IOException e) { System.err.println("Unable to clean up temporary directory '" + tmpDir + "': " + e.getMessage()); } } } } }; Repository manifestRep = new SailRepository(new MemoryStore()); manifestRep.initialize(); RepositoryConnection con = manifestRep.getConnection(); addTurtle(con, new URL(manifestFile), manifestFile); String query = " PREFIX qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> " + "PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> " + "SELECT DISTINCT ?manifestFile " + "WHERE { [] mf:include [ rdf:rest*/rdf:first ?manifestFile ] . } "; TupleQueryResult manifestResults = con.prepareTupleQuery(QueryLanguage.SPARQL, query, manifestFile).evaluate(); while (manifestResults.hasNext()) { BindingSet bindingSet = manifestResults.next(); String subManifestFile = bindingSet.getValue("manifestFile").toString(); System.err.println(subManifestFile); if (includeSubManifest(subManifestFile, excludedSubdirs)) { suite.addTest(SPARQLQueryTest.suite(subManifestFile, factory, approvedTestsOnly)); } } manifestResults.close(); con.close(); manifestRep.shutDown(); logger.info("Created aggregated test suite with " + suite.countTestCases() + " test cases."); return suite; } public static TestSuite suite(SPARQLUpdateConformanceTest.Factory factory, boolean officialWorkingGroupTests, boolean approvedTestsOnly, boolean useRemote, String... excludedSubdirs) throws Exception { final String manifestFile = getManifestFile(officialWorkingGroupTests, useRemote); TestSuite suite = new TestSuite(factory.getClass().getName()) { @Override public void run(TestResult result) { try { super.run(result); } finally { if (tmpDir != null) { try { FileUtil.deleteDir(tmpDir); } catch (IOException e) { System.err.println("Unable to clean up temporary directory '" + tmpDir + "': " + e.getMessage()); } } } } }; Repository manifestRep = new SailRepository(new MemoryStore()); manifestRep.initialize(); RepositoryConnection con = manifestRep.getConnection(); addTurtle(con, new URL(manifestFile), manifestFile); String query = " PREFIX qt: <http://www.w3.org/2001/sw/DataAccess/tests/test-query#> " + "PREFIX mf: <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#> " + "SELECT DISTINCT ?manifestFile " + "WHERE { [] mf:include [ rdf:rest*/rdf:first ?manifestFile ] . } "; TupleQueryResult manifestResults = con.prepareTupleQuery(QueryLanguage.SPARQL, query, manifestFile).evaluate(); while (manifestResults.hasNext()) { BindingSet bindingSet = manifestResults.next(); String subManifestFile = bindingSet.getValue("manifestFile").toString(); if (includeSubManifest(subManifestFile, excludedSubdirs)) { suite.addTest(SPARQLUpdateConformanceTest.suite(subManifestFile, factory, approvedTestsOnly)); } } manifestResults.close(); con.close(); manifestRep.shutDown(); logger.info("Created aggregated test suite with " + suite.countTestCases() + " test cases."); return suite; } private static String getManifestFile(boolean officialWorkingGroupTests, boolean useRemote) { String manifestFile = null; if (useRemote) { manifestFile = "http://www.w3.org/2009/sparql/docs/tests/data-sparql11/manifest-all.ttl"; } else { URL url = null; if (officialWorkingGroupTests) { url = SPARQL11ManifestTest.class.getResource("/testcases-sparql-1.1-w3c/manifest-all.ttl"); } else { url = SPARQL11ManifestTest.class.getResource("/testcases-sparql-1.1/manifest-evaluation.ttl"); } if ("jar".equals(url.getProtocol())) { // Extract manifest files to a temporary directory try { tmpDir = FileUtil.createTempDir("sparql11-test-evaluation"); JarURLConnection con = (JarURLConnection)url.openConnection(); JarFile jar = con.getJarFile(); ZipUtil.extract(jar, tmpDir); File localFile = new File(tmpDir, con.getEntryName()); manifestFile = localFile.toURI().toURL().toString(); } catch (IOException e) { throw new AssertionError(e); } } else { manifestFile = url.toString(); } } return manifestFile; } /** * Verifies if the selected subManifest occurs in the supplied list of * excluded subdirs. * * @param subManifestFile * the url of a sub-manifest * @param excludedSubdirs * an array of directory names. May be null. * @return <code>false</code> if the supplied list of excluded subdirs is not * empty and contains a match for the supplied sub-manifest, * <code>true</code> otherwise. */ private static boolean includeSubManifest(String subManifestFile, String[] excludedSubdirs) { boolean result = true; if (excludedSubdirs != null && excludedSubdirs.length > 0) { int index = subManifestFile.lastIndexOf("/"); String path = subManifestFile.substring(0, index); String sd = path.substring(path.lastIndexOf("/") + 1); for (String subdir : excludedSubdirs) { if (sd.equals(subdir)) { result = false; break; } } } return result; } static void addTurtle(RepositoryConnection con, URL url, String baseURI, Resource... contexts) throws IOException, RepositoryException, RDFParseException { if (baseURI == null) { baseURI = url.toExternalForm(); } InputStream in = url.openStream(); try { OpenRDFUtil.verifyContextNotNull(contexts); final ValueFactory vf = con.getRepository().getValueFactory(); RDFParser rdfParser = new TurtleParser(); rdfParser.setValueFactory(vf); rdfParser.setVerifyData(false); rdfParser.setStopAtFirstError(true); rdfParser.setDatatypeHandling(RDFParser.DatatypeHandling.IGNORE); RDFInserter rdfInserter = new RDFInserter(con); rdfInserter.enforceContext(contexts); rdfParser.setRDFHandler(rdfInserter); con.begin(); try { rdfParser.parse(in, baseURI); con.commit(); } catch (RDFHandlerException e) { con.rollback(); // RDFInserter only throws wrapped RepositoryExceptions throw (RepositoryException)e.getCause(); } catch (RuntimeException e) { con.rollback(); } } finally { in.close(); } } }