blob: d2e236ebc0fdc7b794cc1398d3c98d41fd24b6b8 [file] [log] [blame]
/**
* Copyright (c) 2012 Salzburg Research.
*
* Licensed 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 kiwi.core.test.sparql;
import com.google.code.tempusfugit.concurrency.ConcurrentRule;
import com.google.code.tempusfugit.concurrency.RepeatingRule;
import com.google.code.tempusfugit.concurrency.annotations.Concurrent;
import com.google.code.tempusfugit.concurrency.annotations.Repeating;
import com.google.common.io.Resources;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.parsing.Parser;
import kiwi.core.test.base.LMFBaseTest;
import org.junit.Rule;
import org.junit.Test;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Collections;
import java.util.Iterator;
import java.util.regex.Matcher;
import static com.jayway.restassured.RestAssured.expect;
import static com.jayway.restassured.RestAssured.given;
import static org.hamcrest.Matchers.*;
/**
* Tests the SPARQL Web Service, querying and updating.
*
* @author Sebastian Schaffert
*/
public class SparqlServiceTest extends LMFBaseTest {
@Rule
public ConcurrentRule concurrently = new ConcurrentRule();
@Rule
public RepeatingRule repeatedly = new RepeatingRule();
private final static int THREADS = 5;
private final static int REPETITIONS = 10;
/**
* Test running a SPARQL ASK { ...} query
* @throws IOException
*/
@Test
@Concurrent(count = THREADS)
@Repeating(repetition = REPETITIONS)
public void testSparqlAsk() throws IOException {
RestAssured.registerParser("application/sparql-results+xml", Parser.XML);
RestAssured.registerParser("application/sparql-results+json", Parser.JSON);
// generate some random N3 data
String s1 = generateRandomUri();
String s2 = generateRandomUri();
String s3 = generateRandomUri();
String v1 = generateRandomContent(20);
String v2 = generateRandomContent(15);
String v3 = generateRandomContent(25);
String n3data =
Resources.toString(this.getClass().getResource("data.n3"), Charset.defaultCharset()).
replaceAll("\\$1", Matcher.quoteReplacement(s1)).
replaceAll("\\$2", Matcher.quoteReplacement(s2)).
replaceAll("\\$3", Matcher.quoteReplacement(s3)).
replaceAll("\\$v1", Matcher.quoteReplacement(v1)).
replaceAll("\\$v2", Matcher.quoteReplacement(v2)).
replaceAll("\\$v3", Matcher.quoteReplacement(v3));
// import data using import webservice; result must be 200 ok
given().
header("Content-Type", "text/rdf+n3").
body(n3data).
expect().
statusCode(200).
when().
post("/import/upload");
// carry out SPARQL ASK query for s1 foaf:knows s2; result must be SPARQL/XML and true
String askQuery =
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n"+
"ASK { <$1> foaf:knows <$2> }".
replaceAll("\\$1", s1).
replaceAll("\\$2", s2);
given().
header("Accept", "application/xml").
header("Content-Type","text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body("sparql.boolean", equalTo("true")).
when().
post("/sparql/select");
// carry out SPARQL ASK query for s1 foaf:knows s2; result must be SPARQL/JSON and true
given().
header("Accept", "application/json").
header("Content-Type", "text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+json")).
body("boolean", equalTo(true)).
when().
post("/sparql/select");
// carry out SPARQL ASK query for s1 foaf:knows s2; result must be SPARQL/JSON and true
given().
header("Accept", "text/html").
header("Content-Type", "text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("text/html")).
body("html.head.title", equalTo("SPARQL Query Results")).
when().
post("/sparql/select");
for(String uri : new String[] {s1,s2,s3}) {
// delete the resource
expect().
statusCode(200).
when().
delete("/resource/"+uri.substring(baseResource.length()));
}
}
/**
* Test running a SPARQL SELECT ... WHERE { ... } query
* @throws IOException
*/
@Test
@Concurrent(count = THREADS)
@Repeating(repetition = REPETITIONS)
public void testSparqlSelect() throws IOException {
RestAssured.registerParser("application/sparql-results+xml", Parser.XML);
RestAssured.registerParser("application/sparql-results+json", Parser.JSON);
// register the SPARQL namespace for XPath queries
NamespaceContext ns = new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if("".equals(prefix)) {
return "http://www.w3.org/2005/sparql-results#";
} else if(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) {
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
} else if(XMLConstants.XML_NS_PREFIX.equals(prefix)) {
return XMLConstants.XML_NS_URI;
} else {
return XMLConstants.NULL_NS_URI;
}
}
@Override
public String getPrefix(String namespaceURI) {
if("http://www.w3.org/2005/sparql-results#".equals(namespaceURI)) {
return XMLConstants.DEFAULT_NS_PREFIX;
} else {
return null;
}
}
@Override
public Iterator<String> getPrefixes(String namespaceURI) {
if("http://www.w3.org/2005/sparql-results#".equals(namespaceURI)) {
return Collections.singleton(XMLConstants.DEFAULT_NS_PREFIX).iterator();
} else {
return null;
}
}
};
// generate some random N3 data
String s1 = generateRandomUri();
String s2 = generateRandomUri();
String s3 = generateRandomUri();
String v1 = generateRandomContent(20);
String v2 = generateRandomContent(15);
String v3 = generateRandomContent(25);
String n3data =
Resources.toString(this.getClass().getResource("data.n3"), Charset.defaultCharset()).
replaceAll("\\$1", Matcher.quoteReplacement(s1)).
replaceAll("\\$2", Matcher.quoteReplacement(s2)).
replaceAll("\\$3", Matcher.quoteReplacement(s3)).
replaceAll("\\$v1", Matcher.quoteReplacement(v1)).
replaceAll("\\$v2", Matcher.quoteReplacement(v2)).
replaceAll("\\$v3", Matcher.quoteReplacement(v3));
// import data using import webservice; result must be 200 ok
given().
header("Content-Type", "text/rdf+n3").
body(n3data).
expect().
statusCode(200).
when().
post("/import/upload");
// carry out SPARQL SELECT query, selecting all persons and their names foaf:known by s1; must be s2 and s3
String selectQuery =
("PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n"+
"SELECT ?p ?n " +
"WHERE { <$1> foaf:knows ?p . " +
" ?p foaf:name ?n }").
replaceAll("\\$1", s1);
given().
header("Accept", "application/xml").
header("Content-Type", "text/plain").
body(selectQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body(hasXPath("/sparql/results/result/binding[@name='p']/uri", ns, isOneOf(s2, s3))).
body(hasXPath("/sparql/results/result/binding[@name='n']/literal", ns, isOneOf(v2, v3))).
when().
post("/sparql/select");
// carry out SPARQL ASK query for s1 foaf:knows s2; result must be SPARQL/JSON and true
given().
header("Accept", "application/json").
header("Content-Type", "text/plain").
body(selectQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+json")).
body("results.bindings.p.value", hasItems(s2, s3)).
body("results.bindings.n.value", hasItems(v2, v3)).
when().
post("/sparql/select");
// carry out SPARQL ASK query for s1 foaf:knows s2; result must be SPARQL/JSON and true
given().
header("Accept", "text/html").
header("Content-Type", "text/plain").
body(selectQuery).
expect().
statusCode(200).
header("Content-Type", containsString("text/html")).
body("html.head.title", equalTo("SPARQL Query Results")).
when().
post("/sparql/select");
for(String uri : new String[] {s1,s2,s3}) {
// delete the resource
expect().
statusCode(200).
when().
delete("/resource/"+uri.substring(baseResource.length()));
}
}
/**
* Test running SPARQL INSERT DATA { ... } statements
* @throws IOException
*/
@Test
@Concurrent(count = THREADS)
@Repeating(repetition = REPETITIONS)
public void testSparqlInsertData() throws IOException {
RestAssured.registerParser("application/sparql-results+xml", Parser.XML);
RestAssured.registerParser("application/sparql-results+json", Parser.JSON);
// generate some random N3 data
String s1 = generateRandomUri();
String s2 = generateRandomUri();
String s3 = generateRandomUri();
String v1 = generateRandomContent(20);
String v2 = generateRandomContent(15);
String v3 = generateRandomContent(25);
String n3data =
Resources.toString(this.getClass().getResource("data.n3"),Charset.defaultCharset()).
replaceAll("\\$1", Matcher.quoteReplacement(s1)).
replaceAll("\\$2", Matcher.quoteReplacement(s2)).
replaceAll("\\$3", Matcher.quoteReplacement(s3)).
replaceAll("\\$v1", Matcher.quoteReplacement(v1)).
replaceAll("\\$v2", Matcher.quoteReplacement(v2)).
replaceAll("\\$v3", Matcher.quoteReplacement(v3));
// import base data using import webservice; result must be 200 ok
given().
header("Content-Type", "text/rdf+n3").
body(n3data).
expect().
statusCode(200).
when().
post("/import/upload");
// check that not(s2 foaf:knows s3)
String askQuery =
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n"+
"ASK { <$2> foaf:knows <$3> }".
replaceAll("\\$3", s3).
replaceAll("\\$2", s2);
given().
header("Accept", "application/xml").
header("Content-Type","text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body("sparql.boolean", equalTo("false")).
when().
post("/sparql/select");
// load SPARQL INSERT from file insert.sparql
String sparqlInsert = Resources.toString(this.getClass().getResource("insert.sparql"), Charset.defaultCharset()).
replaceAll("\\$1",s1).
replaceAll("\\$2", s2).
replaceAll("\\$3", s3);
// execute insert by posting it to the /sparql/update webservice, expect 200
given().
header("Content-Type", "text/plain").
body(sparqlInsert).
expect().
statusCode(200).
when().
post("/sparql/update");
// now expect the ASK query to yield "true"
given().
header("Accept", "application/xml").
header("Content-Type", "text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body("sparql.boolean", equalTo("true")).
when().
post("/sparql/select");
for(String uri : new String[] {s1,s2,s3}) {
// delete the resource
expect().
statusCode(200).
when().
delete("/resource/"+uri.substring(baseResource.length()));
}
}
/**
* Test running SPARQL INSERT { ... } WHERE { ... } statements
* @throws IOException
*/
@Test
// no concurrency, since the tests themselves and update programs are not thread safe
@Repeating(repetition = REPETITIONS)
public void testSparqlInsertWhere() throws IOException {
RestAssured.registerParser("application/sparql-results+xml", Parser.XML);
RestAssured.registerParser("application/sparql-results+json", Parser.JSON);
// generate some random N3 data
String s1 = generateRandomUri();
String s2 = generateRandomUri();
String s3 = generateRandomUri();
String v1 = generateRandomContent(20);
String v2 = generateRandomContent(15);
String v3 = generateRandomContent(25);
String n3data =
Resources.toString(this.getClass().getResource("data.n3"),Charset.defaultCharset()).
replaceAll("\\$1", Matcher.quoteReplacement(s1)).
replaceAll("\\$2", Matcher.quoteReplacement(s2)).
replaceAll("\\$3", Matcher.quoteReplacement(s3)).
replaceAll("\\$v1", Matcher.quoteReplacement(v1)).
replaceAll("\\$v2", Matcher.quoteReplacement(v2)).
replaceAll("\\$v3", Matcher.quoteReplacement(v3));
// import base data using import webservice; result must be 200 ok
given().
header("Content-Type", "text/rdf+n3").
body(n3data).
expect().
statusCode(200).
when().
post("/import/upload");
// check that not(s2 foaf:knows s3)
String askQuery =
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n"+
"ASK { <$2> foaf:knows <$3> }".
replaceAll("\\$3", s3).
replaceAll("\\$2", s2);
given().
header("Accept", "application/xml").
header("Content-Type","text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body("sparql.boolean", equalTo("false")).
when().
post("/sparql/select");
// load SPARQL INSERT from file insert.sparql
String sparqlInsert = Resources.toString(this.getClass().getResource("update.sparql"), Charset.defaultCharset());
// execute insert by posting it to the /sparql/update webservice, expect 200
given().
header("Content-Type", "text/plain").
body(sparqlInsert).
expect().
statusCode(200).
when().
post("/sparql/update");
// now expect the ASK query to yield "true"
given().
header("Accept", "application/xml").
header("Content-Type","text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body("sparql.boolean", equalTo("true")).
when().
post("/sparql/select");
for(String uri : new String[] {s1,s2,s3}) {
// delete the resource
expect().
statusCode(200).
when().
delete("/resource/"+uri.substring(baseResource.length()));
}
}
/**
* Test running SPARQL DELETE updates
* @throws IOException
*/
@Test
// no concurrency, since the tests themselves and update programs are not thread safe
@Repeating(repetition = REPETITIONS)
public void testSparqlDelete() throws IOException {
RestAssured.registerParser("application/sparql-results+xml", Parser.XML);
RestAssured.registerParser("application/sparql-results+json", Parser.JSON);
// generate some random N3 data
String s1 = generateRandomUri();
String s2 = generateRandomUri();
String s3 = generateRandomUri();
String v1 = generateRandomContent(20);
String v2 = generateRandomContent(15);
String v3 = generateRandomContent(25);
String n3data =
Resources.toString(this.getClass().getResource("data.n3"), Charset.defaultCharset()).
replaceAll("\\$1", Matcher.quoteReplacement(s1)).
replaceAll("\\$2", Matcher.quoteReplacement(s2)).
replaceAll("\\$3", Matcher.quoteReplacement(s3)).
replaceAll("\\$v1", Matcher.quoteReplacement(v1)).
replaceAll("\\$v2", Matcher.quoteReplacement(v2)).
replaceAll("\\$v3", Matcher.quoteReplacement(v3));
// import base data using import webservice; result must be 200 ok
given().
header("Content-Type", "text/rdf+n3").
body(n3data).
expect().
statusCode(200).
when().
post("/import/upload");
// check that s1 foaf:knows s2
String askQuery =
"PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n"+
"ASK { <$1> foaf:knows <$2> }".
replaceAll("\\$1", s1).
replaceAll("\\$2", s2);
given().
header("Accept", "application/xml").
header("Content-Type","text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body("sparql.boolean", equalTo("true")).
when().
post("/sparql/select");
// load SPARQL DELETE from file delete.sparql
String sparqlInsert = Resources.toString(this.getClass().getResource("delete.sparql"), Charset.defaultCharset());
// execute insert by posting it to the /sparql/update webservice, expect 200
given().
header("Content-Type","text/plain").
body(sparqlInsert).
expect().
statusCode(200).
when().
post("/sparql/update");
// now expect the ASK query to yield "false"
given().
header("Accept", "application/xml").
header("Content-Type","text/plain").
body(askQuery).
expect().
statusCode(200).
header("Content-Type", containsString("application/sparql-results+xml")).
body("sparql.boolean", equalTo("false")).
when().
post("/sparql/select");
for(String uri : new String[] {s1,s2,s3}) {
// delete the resource
expect().
statusCode(200).
when().
delete("/resource/"+uri.substring(baseResource.length()));
}
}
}