Package org.openrdf.query.parser.sparql

Source Code of org.openrdf.query.parser.sparql.SPARQLQueryTest$Factory

/*
* Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2008.
*
* Licensed under the Aduna BSD-style license.
*/
package org.openrdf.query.parser.sparql;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import junit.framework.TestCase;
import junit.framework.TestSuite;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import info.aduna.io.IOUtil;
import info.aduna.text.StringUtil;

import org.openrdf.model.Resource;
import org.openrdf.model.Statement;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.util.ModelUtil;
import org.openrdf.query.BindingSet;
import org.openrdf.query.BooleanQuery;
import org.openrdf.query.Dataset;
import org.openrdf.query.EvaluationException;
import org.openrdf.query.GraphQuery;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.Query;
import org.openrdf.query.QueryLanguage;
import org.openrdf.query.TupleQuery;
import org.openrdf.query.dawg.DAWGTestResultSetUtil;
import org.openrdf.query.impl.DatasetImpl;
import org.openrdf.query.resultio.BooleanQueryResultFormat;
import org.openrdf.query.resultio.BooleanQueryResultParserRegistry;
import org.openrdf.query.resultio.QueryResultIO;
import org.openrdf.query.resultio.TupleQueryResultFormat;
import org.openrdf.query.resultio.TupleQueryResultParser;
import org.openrdf.repository.Repository;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.repository.sail.SailRepository;
import org.openrdf.repository.util.RDFInserter;
import org.openrdf.result.GraphResult;
import org.openrdf.result.TupleResult;
import org.openrdf.result.impl.MutableTupleResult;
import org.openrdf.result.util.QueryResultUtil;
import org.openrdf.result.util.TupleQueryResultBuilder;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFParser;
import org.openrdf.rio.Rio;
import org.openrdf.rio.RDFParser.DatatypeHandling;
import org.openrdf.rio.helpers.StatementCollector;
import org.openrdf.sail.memory.MemoryStore;
import org.openrdf.store.StoreException;

public abstract class SPARQLQueryTest extends TestCase {

  /*-----------*
   * Constants *
   *-----------*/

  static final Logger logger = LoggerFactory.getLogger(SPARQLQueryTest.class);

  protected final String testURI;

  protected final String queryFileURL;

  protected final String resultFileURL;

  protected final Dataset dataset;

  protected final boolean laxCardinality;

  /*-----------*
   * Variables *
   *-----------*/

  protected Repository dataRep;

  protected RepositoryConnection con;

  /*--------------*
   * Constructors *
   *--------------*/

  public SPARQLQueryTest(String testURI, String name, String queryFileURL, String resultFileURL,
      Dataset dataSet, boolean laxCardinality)
  {
    super(name);

    this.testURI = testURI;
    this.queryFileURL = queryFileURL;
    this.resultFileURL = resultFileURL;
    this.dataset = dataSet;
    this.laxCardinality = laxCardinality;
  }

  /*---------*
   * Methods *
   *---------*/

  @Override
  protected void setUp()
    throws Exception
  {
    dataRep = createRepository();

    if (dataset != null) {
      try {
        uploadDataset(dataset);
      }
      catch (Exception exc) {
        try {
          dataRep.shutDown();
          dataRep = null;
        }
        catch (Exception e2) {
          logger.error(e2.toString(), e2);
        }
        throw exc;
      }
    }

    con = dataRep.getConnection();
  }

  protected Repository createRepository()
    throws Exception
  {
    Repository repo = newRepository();
    repo.initialize();
    RepositoryConnection con = repo.getConnection();
    try {
      con.clear();
      con.clearNamespaces();
    }
    finally {
      con.close();
    }
    return repo;
  }

  protected abstract Repository newRepository()
    throws Exception;

  @Override
  protected void tearDown()
    throws Exception
  {
    if (con != null) {
      con.close();
      con = null;
    }

    if (dataRep != null) {
      dataRep.shutDown();
      dataRep = null;
    }
  }

  @Override
  protected void runTest()
    throws Exception
  {
    String queryString = readQueryString();
    Query query = prepareQuery(queryString);

    if (query instanceof TupleQuery) {
      TupleResult queryResult = ((TupleQuery)query).evaluate();

      TupleResult expectedResult = readExpectedTupleQueryResult();
      compareTupleQueryResults(queryResult, expectedResult);

      // Graph queryGraph = RepositoryUtil.asGraph(queryResult);
      // Graph expectedGraph = readExpectedTupleQueryResult();
      // compareGraphs(queryGraph, expectedGraph);
    }
    else if (query instanceof GraphQuery) {
      GraphResult gqr = ((GraphQuery)query).evaluate();
      Set<Statement> queryResult = gqr.asSet();

      Set<Statement> expectedResult = readExpectedGraphQueryResult();

      compareGraphs(queryResult, expectedResult);
    }
    else if (query instanceof BooleanQuery) {
      boolean queryResult = ((BooleanQuery)query).ask();
      boolean expectedResult = readExpectedBooleanQueryResult();
      assertEquals(expectedResult, queryResult);
    }
    else {
      throw new RuntimeException("Unexpected query type: " + query.getClass());
    }
  }

  protected Query prepareQuery(String queryString)
    throws StoreException
  {
    Query query = con.prepareQuery(QueryLanguage.SPARQL, queryString, queryFileURL);
    if (dataset != null) {
      query.setDataset(dataset);
    }
    return query;
  }

  private void compareTupleQueryResults(TupleResult queryResult, TupleResult expectedResult)
    throws Exception
  {
    // Create MutableTupleQueryResult to be able to re-iterate over the
    // results
    MutableTupleResult queryResultTable = new MutableTupleResult(queryResult);
    MutableTupleResult expectedResultTable = new MutableTupleResult(expectedResult);

    boolean resultsEqual;
    if (laxCardinality) {
      resultsEqual = QueryResultUtil.isSubset(queryResultTable, expectedResultTable);
    }
    else {
      resultsEqual = QueryResultUtil.equals(queryResultTable, expectedResultTable);
    }

    if (!resultsEqual) {
      queryResultTable.beforeFirst();
      expectedResultTable.beforeFirst();

      /*
       * StringBuilder message = new StringBuilder(128);
       * message.append("\n============ "); message.append(getName());
       * message.append(" =======================\n");
       * message.append("Expected result: \n"); while
       * (expectedResultTable.hasNext()) {
       * message.append(expectedResultTable.next()); message.append("\n"); }
       * message.append("============="); StringUtil.appendN('=',
       * getName().length(), message);
       * message.append("========================\n"); message.append("Query
       * result: \n"); while (queryResultTable.hasNext()) {
       * message.append(queryResultTable.next()); message.append("\n"); }
       * message.append("============="); StringUtil.appendN('=',
       * getName().length(), message);
       * message.append("========================\n");
       */

      List<BindingSet> queryBindings = queryResultTable.asList();
      List<BindingSet> expectedBindings = expectedResultTable.asList();

      List<BindingSet> missingBindings = new ArrayList<BindingSet>(expectedBindings);
      missingBindings.removeAll(queryBindings);

      List<BindingSet> unexpectedBindings = new ArrayList<BindingSet>(queryBindings);
      unexpectedBindings.removeAll(expectedBindings);

      StringBuilder message = new StringBuilder(128);
      message.append("\n============ ");
      message.append(getName());
      message.append(" =======================\n");

      if (!missingBindings.isEmpty()) {
        message.append("Missing bindings: \n");
        for (BindingSet bs : missingBindings) {
          message.append(bs);
          message.append("\n");
        }

        message.append("=============");
        StringUtil.appendN('=', getName().length(), message);
        message.append("========================\n");
      }

      if (!unexpectedBindings.isEmpty()) {
        message.append("Unexpected bindings: \n");
        for (BindingSet bs : unexpectedBindings) {
          message.append(bs);
          message.append("\n");
        }

        message.append("=============");
        StringUtil.appendN('=', getName().length(), message);
        message.append("========================\n");
      }

      logger.error(message.toString());
      fail(message.toString());
    }
  }

  private void compareGraphs(Set<Statement> queryResult, Set<Statement> expectedResult)
    throws Exception
  {
    if (!ModelUtil.equals(expectedResult, queryResult)) {
      // Don't use RepositoryUtil.difference, it reports incorrect diffs
      /*
       * Collection<? extends Statement> unexpectedStatements =
       * RepositoryUtil.difference(queryResult, expectedResult); Collection<?
       * extends Statement> missingStatements =
       * RepositoryUtil.difference(expectedResult, queryResult);
       * StringBuilder message = new StringBuilder(128);
       * message.append("\n=======Diff: "); message.append(getName());
       * message.append("========================\n"); if
       * (!unexpectedStatements.isEmpty()) { message.append("Unexpected
       * statements in result: \n"); for (Statement st :
       * unexpectedStatements) { message.append(st.toString());
       * message.append("\n"); } message.append("============="); for (int i =
       * 0; i < getName().length(); i++) { message.append("="); }
       * message.append("========================\n"); } if
       * (!missingStatements.isEmpty()) { message.append("Statements missing
       * in result: \n"); for (Statement st : missingStatements) {
       * message.append(st.toString()); message.append("\n"); }
       * message.append("============="); for (int i = 0; i <
       * getName().length(); i++) { message.append("="); }
       * message.append("========================\n"); }
       */
      StringBuilder message = new StringBuilder(128);
      message.append("\n============ ");
      message.append(getName());
      message.append(" =======================\n");
      message.append("Expected result: \n");
      for (Statement st : expectedResult) {
        message.append(st.toString());
        message.append("\n");
      }
      message.append("=============");
      StringUtil.appendN('=', getName().length(), message);
      message.append("========================\n");

      message.append("Query result: \n");
      for (Statement st : queryResult) {
        message.append(st.toString());
        message.append("\n");
      }
      message.append("=============");
      StringUtil.appendN('=', getName().length(), message);
      message.append("========================\n");

      logger.error(message.toString());
      fail(message.toString());
    }
  }

  private void uploadDataset(Dataset dataset)
    throws Exception
  {
    RepositoryConnection con = dataRep.getConnection();
    try {
      // Merge default and named graphs to filter duplicates
      Set<URI> graphURIs = new HashSet<URI>();
      graphURIs.addAll(dataset.getDefaultGraphs());
      graphURIs.addAll(dataset.getNamedGraphs());

      for (Resource graphURI : graphURIs) {
        upload(((URI)graphURI), graphURI);
      }
    }
    finally {
      con.close();
    }
  }

  private void upload(URI graphURI, Resource context)
    throws Exception
  {
    RepositoryConnection con = dataRep.getConnection();

    con.begin();
    try {
      RDFFormat rdfFormat = Rio.getParserFormatForFileName(graphURI.toString(), RDFFormat.TURTLE);
      RDFParser rdfParser = Rio.createParser(rdfFormat, con.getValueFactory());
      rdfParser.setVerifyData(false);
      rdfParser.setDatatypeHandling(DatatypeHandling.IGNORE);
      // rdfParser.setPreserveBNodeIDs(true);

      RDFInserter rdfInserter = new RDFInserter(con);
      rdfInserter.enforceContext(context);
      rdfParser.setRDFHandler(rdfInserter);

      URL graphURL = new URL(graphURI.toString());
      InputStream in = graphURL.openStream();
      try {
        rdfParser.parse(in, graphURI.toString());
      }
      finally {
        in.close();
      }

      con.commit();
    }
    finally {
      con.close();
    }
  }

  private String readQueryString()
    throws IOException
  {
    InputStream stream = new URL(queryFileURL).openStream();
    try {
      return IOUtil.readString(new InputStreamReader(stream, "UTF-8"));
    }
    finally {
      stream.close();
    }
  }

  private TupleResult readExpectedTupleQueryResult()
    throws Exception
  {
    TupleQueryResultFormat tqrFormat = QueryResultIO.getParserFormatForFileName(resultFileURL);

    if (tqrFormat != null) {
      InputStream in = new URL(resultFileURL).openStream();
      try {
        TupleQueryResultParser parser = QueryResultIO.createParser(tqrFormat);

        TupleQueryResultBuilder qrBuilder = new TupleQueryResultBuilder();
        parser.setTupleQueryResultHandler(qrBuilder);

        parser.parse(in);
        return qrBuilder.getQueryResult();
      }
      finally {
        in.close();
      }
    }
    else {
      Set<Statement> resultGraph = readExpectedGraphQueryResult();
      return DAWGTestResultSetUtil.toTupleQueryResult(resultGraph);
    }
  }

  private boolean readExpectedBooleanQueryResult()
    throws Exception
  {
    BooleanQueryResultFormat bqrFormat = BooleanQueryResultParserRegistry.getInstance().getFileFormatForFileName(
        resultFileURL);

    if (bqrFormat != null) {
      InputStream in = new URL(resultFileURL).openStream();
      try {
        return QueryResultIO.parse(in, bqrFormat);
      }
      finally {
        in.close();
      }
    }
    else {
      Set<Statement> resultGraph = readExpectedGraphQueryResult();
      return DAWGTestResultSetUtil.toBooleanQueryResult(resultGraph);
    }
  }

  private Set<Statement> readExpectedGraphQueryResult()
    throws Exception
  {
    RDFFormat rdfFormat = Rio.getParserFormatForFileName(resultFileURL);

    if (rdfFormat != null) {
      RDFParser parser = Rio.createParser(rdfFormat);
      parser.setDatatypeHandling(DatatypeHandling.IGNORE);
      parser.setPreserveBNodeIDs(true);

      Set<Statement> result = new LinkedHashSet<Statement>();
      parser.setRDFHandler(new StatementCollector(result));

      InputStream in = new URL(resultFileURL).openStream();
      try {
        parser.parse(in, resultFileURL);
      }
      finally {
        in.close();
      }

      return result;
    }
    else {
      throw new RuntimeException("Unable to determine file type of results file");
    }
  }

  public interface Factory {

    SPARQLQueryTest createSPARQLQueryTest(String testURI, String name, String queryFileURL,
        String resultFileURL, Dataset dataSet, boolean laxCardinality);
  }

  public static TestSuite suite(String manifestFileURL, Factory factory)
    throws Exception
  {
    logger.info("Building test suite for {}", manifestFileURL);

    TestSuite suite = new TestSuite(factory.getClass().getName());

    // Read manifest and create declared test cases
    Repository manifestRep = new SailRepository(new MemoryStore());
    manifestRep.initialize();
    RepositoryConnection con = manifestRep.getConnection();

    ManifestTest.addTurtle(con, new URL(manifestFileURL), manifestFileURL);

    suite.setName(getManifestName(manifestRep, con, manifestFileURL));

    // Extract test case information from the manifest file. Note that we only
    // select those test cases that are mentioned in the list.
    StringBuilder query = new StringBuilder(512);
    query.append(" SELECT DISTINCT testURI, testName, resultFile, action, queryFile, defaultGraph ");
    query.append(" FROM {} rdf:first {testURI} dawgt:approval {dawgt:Approved}; ");
    query.append("                             mf:name {testName}; ");
    query.append("                             mf:result {resultFile}; ");
    query.append("                             mf:action {action} qt:query {queryFile}; ");
    query.append("                                               [qt:data {defaultGraph}] ");
    query.append(" USING NAMESPACE ");
    query.append("  mf = <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#>, ");
    query.append("  dawgt = <http://www.w3.org/2001/sw/DataAccess/tests/test-dawg#>, ");
    query.append("  qt = <http://www.w3.org/2001/sw/DataAccess/tests/test-query#>");
    TupleQuery testCaseQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query.toString());

    query.setLength(0);
    query.append(" SELECT graph ");
    query.append(" FROM {action} qt:graphData {graph} ");
    query.append(" USING NAMESPACE ");
    query.append(" qt = <http://www.w3.org/2001/sw/DataAccess/tests/test-query#>");
    TupleQuery namedGraphsQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query.toString());

    query.setLength(0);
    query.append("SELECT 1 ");
    query.append(" FROM {testURI} mf:resultCardinality {mf:LaxCardinality}");
    query.append(" USING NAMESPACE mf = <http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#>");
    TupleQuery laxCardinalityQuery = con.prepareTupleQuery(QueryLanguage.SERQL, query.toString());

    logger.debug("evaluating query..");
    TupleResult testCases = testCaseQuery.evaluate();
    while (testCases.hasNext()) {
      BindingSet bindingSet = testCases.next();

      URI testURI = (URI)bindingSet.getValue("testURI");
      String testName = bindingSet.getValue("testName").toString();
      String resultFile = bindingSet.getValue("resultFile").toString();
      String queryFile = bindingSet.getValue("queryFile").toString();
      URI defaultGraphURI = (URI)bindingSet.getValue("defaultGraph");
      Value action = bindingSet.getValue("action");

      logger.debug("found test case : {}", testName);

      // Query named graphs
      namedGraphsQuery.setBinding("action", action);
      TupleResult namedGraphs = namedGraphsQuery.evaluate();

      DatasetImpl dataset = null;

      if (defaultGraphURI != null || namedGraphs.hasNext()) {
        dataset = new DatasetImpl();

        if (defaultGraphURI != null) {
          dataset.addDefaultGraph(defaultGraphURI);
        }

        while (namedGraphs.hasNext()) {
          BindingSet graphBindings = namedGraphs.next();
          URI namedGraphURI = (URI)graphBindings.getValue("graph");
          dataset.addNamedGraph(namedGraphURI);
        }
      }

      // Check for lax-cardinality conditions
      boolean laxCardinality = false;
      laxCardinalityQuery.setBinding("testURI", testURI);
      TupleResult laxCardinalityResult = laxCardinalityQuery.evaluate();
      try {
        laxCardinality = laxCardinalityResult.hasNext();
      }
      finally {
        laxCardinalityResult.close();
      }

      SPARQLQueryTest test = factory.createSPARQLQueryTest(testURI.toString(), testName, queryFile,
          resultFile, dataset, laxCardinality);
      if (test != null) {
        suite.addTest(test);
      }
    }

    testCases.close();
    con.close();

    manifestRep.shutDown();
    logger.info("Created test suite with " + suite.countTestCases() + " test cases.");
    return suite;
  }

  protected static String getManifestName(Repository manifestRep, RepositoryConnection con,
      String manifestFileURL)
    throws EvaluationException, StoreException, MalformedQueryException
  {
    // Try to extract suite name from manifest file
    TupleQuery manifestNameQuery = con.prepareTupleQuery(QueryLanguage.SERQL,
        "SELECT ManifestName FROM {ManifestURL} rdfs:label {ManifestName}");
    manifestNameQuery.setBinding("ManifestURL", con.getValueFactory().createURI(manifestFileURL));
    TupleResult manifestNames = manifestNameQuery.evaluate();
    try {
      if (manifestNames.hasNext()) {
        return manifestNames.next().getValue("ManifestName").stringValue();
      }
    }
    finally {
      manifestNames.close();
    }

    // Derive name from manifest URL
    int lastSlashIdx = manifestFileURL.lastIndexOf('/');
    int secLastSlashIdx = manifestFileURL.lastIndexOf('/', lastSlashIdx - 1);
    return manifestFileURL.substring(secLastSlashIdx + 1, lastSlashIdx);
  }
}
TOP

Related Classes of org.openrdf.query.parser.sparql.SPARQLQueryTest$Factory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.