/* * 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.jena.reasoner.rulesys.test; import java.io.BufferedReader ; import java.io.FileReader ; import java.io.IOException ; import java.io.Reader ; import org.apache.jena.rdf.model.* ; import org.apache.jena.reasoner.InfGraph ; import org.apache.jena.reasoner.Reasoner ; import org.apache.jena.reasoner.ReasonerFactory ; import org.apache.jena.reasoner.rulesys.FBRuleInfGraph ; import org.apache.jena.reasoner.test.WGReasonerTester ; import org.apache.jena.shared.JenaException ; import org.apache.jena.util.FileManager ; import org.apache.jena.vocabulary.RDF ; import org.apache.jena.vocabulary.ReasonerVocabulary ; import org.junit.Assert ; import junit.framework.TestCase ; import org.slf4j.Logger ; import org.slf4j.LoggerFactory ; /** * A test harness for running the OWL working group tests. This * differs from the RDF one in several ways (separate manifest files, * different namespaces, document references lack suffix ...). * <p> * This version is used for running the core entailment tests as part of unit testing. * A separate test harness for use in reporting OWL conformance is being developed and * some code rationalization might be once once that stabilizes. </p> */ public class OWLWGTester { /** The base URI in which the files are purported to reside */ public static String BASE_URI = "http://www.w3.org/2002/03owlt/"; /** The base directory in which the test data is actually stored */ public static String baseDir = "testing/wg/"; /** The namespace for the test specification schema */ public static final String NS_OTEST = "http://www.w3.org/2002/03owlt/testOntology#"; /** The namespace for the test specification schema */ public static final String NS_RTEST = "http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#"; /** The rdf class for positive tests */ public static final Resource PositiveEntailmentTest; /** The rdf class for positive tests */ public static final Resource NegativeEntailmentTest; /** The predicate defining the description of the test */ public static final Property descriptionP; /** The predicate defining a premise for the test */ public static final Property premiseDocumentP; /** The predicate defining the conclusion from the test */ public static final Property conclusionDocumentP; /** The predicate defining the status of the test */ public static final Property statusP; /** The reasoner factory being tested */ protected ReasonerFactory reasonerF; /** The configuration information for the reasoner */ protected Resource configuration; /** The test case which has invoke this test */ protected TestCase testcase; /** The processing time used since testcase creation */ protected static long timeCost = 0; /** The total number of tests run */ protected static int numTests = 0; protected static Logger logger = LoggerFactory.getLogger(OWLWGTester.class); // Static initializer for the predicates static { PositiveEntailmentTest = ResourceFactory.createProperty(NS_OTEST, "PositiveEntailmentTest"); NegativeEntailmentTest = ResourceFactory.createProperty(NS_OTEST, "NegativeEntailmentTest"); descriptionP = ResourceFactory.createProperty(NS_RTEST, "description"); premiseDocumentP = ResourceFactory.createProperty(NS_RTEST, "premiseDocument"); conclusionDocumentP = ResourceFactory.createProperty(NS_RTEST, "conclusionDocument"); statusP = ResourceFactory.createProperty(NS_RTEST, "status"); } /** * Constructor * @param reasonerF the factory for the reasoner to be tested * @param testcase the JUnit test case which is requesting this test * @param configuration optional configuration information */ public OWLWGTester(ReasonerFactory reasonerF, TestCase testcase, Resource configuration) { this.reasonerF = reasonerF; this.testcase = testcase; this.configuration = configuration; } /** * Run all the tests in the manifest * @param manifestFile the name of the manifest file relative to baseDir * @param log set to true to enable derivation logging * @param stats set to true to log performance statistics * @return true if all the tests pass * @throws IOException if one of the test files can't be found */ public boolean runTests(String manifestFile, boolean log, boolean stats) throws IOException { // Load up the manifest Model manifest = FileManager.get().loadModel(baseDir + manifestFile); ResIterator tests = manifest.listResourcesWithProperty(RDF.type, PositiveEntailmentTest); while (tests.hasNext()) { Resource test = tests.nextResource(); if (!runTest(test, log, stats)) return false; } tests = manifest.listResourcesWithProperty(RDF.type, NegativeEntailmentTest); while (tests.hasNext()) { Resource test = tests.nextResource(); if (!runTest(test, log, stats)) return false; } return true; } /** * Run a single designated test. * @param test the root node descibing the test * @param log set to true to enable derivation logging * @param stats set to true to log performance statistics * @return true if the test passes * @throws IOException if one of the test files can't be found */ public boolean runTest(Resource test, boolean log, boolean stats) throws IOException { // Find the specification for the named test RDFNode testType = test.getRequiredProperty(RDF.type).getObject(); if (!(testType.equals(NegativeEntailmentTest) || testType.equals(PositiveEntailmentTest) ) ) { throw new JenaException("Can't find test: " + test); } String description = test.getRequiredProperty(descriptionP).getObject().toString(); String status = test.getRequiredProperty(statusP).getObject().toString(); logger.debug("WG test " + test.getURI() + " - " + status); // Load up the premise documents Model premises = ModelFactory.createDefaultModel(); for (StmtIterator premisesI = test.listProperties(premiseDocumentP); premisesI.hasNext(); ) { premises.add(loadFile(premisesI.nextStatement().getObject().toString() + ".rdf")); } // Load up the conclusions document Resource conclusionsRes = (Resource) test.getRequiredProperty(conclusionDocumentP).getObject(); Model conclusions = loadFile(conclusionsRes.toString() + ".rdf"); // Construct the inferred graph // Optional logging if (log) { if (configuration == null) { Model m = ModelFactory.createDefaultModel(); configuration = m.createResource(); } configuration.addProperty(ReasonerVocabulary.PROPtraceOn, "true") .addProperty(ReasonerVocabulary.PROPderivationLogging, "true"); } Reasoner reasoner = reasonerF.create(configuration); long t1 = System.currentTimeMillis(); InfGraph graph = reasoner.bind(premises.getGraph()); Model result = ModelFactory.createModelForGraph(graph); if (stats && graph instanceof FBRuleInfGraph) { // ((FBRuleInfGraph)graph).resetLPProfile(true); } // Check the results against the official conclusions boolean correct = true; if (testType.equals(PositiveEntailmentTest)) { correct = WGReasonerTester.testConclusions(conclusions.getGraph(), result.getGraph()); } else { // A negative entailment check correct = !WGReasonerTester.testConclusions(conclusions.getGraph(), result.getGraph()); } long t2 = System.currentTimeMillis(); timeCost += (t2-t1); numTests++; if (stats) { logger.info("Time=" + (t2-t1) + "ms for " + test.getURI()); printStats(); if (graph instanceof FBRuleInfGraph) { ((FBRuleInfGraph)graph).printLPProfile(); } } if (!correct) { // List all the forward deductions for debugging // if (graph instanceof FBRuleInfGraph) { // System.out.println("Error: deductions graph was ..."); // FBRuleInfGraph fbGraph = (FBRuleInfGraph)graph; // Graph deductions = fbGraph.getDeductionsGraph(); // org.apache.jena.PrintUtil.printOut(deductions.find(null,null,null)); // } } // Signal the results if (testcase != null) { Assert.assertTrue("Test: " + test + "\n" + reasonerF.getURI() + "\n" + description, correct); } return correct; } /** * Utility to load a file as a Model. * Files are assumed to be relative to the BASE_URI. * @param file the file name, relative to baseDir * @return the loaded Model */ public static Model loadFile(String file) throws IOException { String langType = "RDF/XML"; if (file.endsWith(".nt")) { langType = "N-TRIPLE"; } else if (file.endsWith("n3")) { langType = "N3"; } Model result = ModelFactory.createDefaultModel(); String fname = file; if (fname.startsWith(BASE_URI)) { fname = fname.substring(BASE_URI.length()); } Reader reader = new BufferedReader(new FileReader(baseDir + fname)); result.read(reader, BASE_URI + fname, langType); return result; } /** * Log (info level) some summary information on the timecost of the tests. */ public void printStats() { logger.info("Ran " + numTests +" in " + timeCost +"ms = " + (timeCost/numTests) + "ms/test"); } }