/*
* (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others.
*
* 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.
*
* Contributors:
* Anahide Tchertchian
* Florent Guillaume
*/
package org.nuxeo.ecm.platform.relations;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.nuxeo.common.utils.FileUtils;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.test.CoreFeature;
import org.nuxeo.ecm.core.test.annotations.Granularity;
import org.nuxeo.ecm.core.test.annotations.RepositoryConfig;
import org.nuxeo.ecm.platform.relations.api.Literal;
import org.nuxeo.ecm.platform.relations.api.Node;
import org.nuxeo.ecm.platform.relations.api.QNameResource;
import org.nuxeo.ecm.platform.relations.api.QueryResult;
import org.nuxeo.ecm.platform.relations.api.RelationManager;
import org.nuxeo.ecm.platform.relations.api.Resource;
import org.nuxeo.ecm.platform.relations.api.Statement;
import org.nuxeo.ecm.platform.relations.api.impl.BlankImpl;
import org.nuxeo.ecm.platform.relations.api.impl.LiteralImpl;
import org.nuxeo.ecm.platform.relations.api.impl.QNameResourceImpl;
import org.nuxeo.ecm.platform.relations.api.impl.RelationDate;
import org.nuxeo.ecm.platform.relations.api.impl.ResourceImpl;
import org.nuxeo.ecm.platform.relations.api.impl.StatementImpl;
import org.nuxeo.ecm.platform.relations.api.util.RelationConstants;
import org.nuxeo.ecm.platform.relations.descriptors.GraphDescriptor;
import org.nuxeo.runtime.api.Framework;
import org.nuxeo.runtime.test.runner.Deploy;
import org.nuxeo.runtime.test.runner.Features;
import org.nuxeo.runtime.test.runner.FeaturesRunner;
import org.nuxeo.runtime.test.runner.LocalDeploy;
@RunWith(FeaturesRunner.class)
@Features(CoreFeature.class)
@RepositoryConfig(cleanup = Granularity.METHOD)
@Deploy("org.nuxeo.ecm.relations")
@LocalDeploy("org.nuxeo.ecm.relations.tests:relation-core-test-contrib.xml")
public class TestCoreGraph {
public static final String DC_TERMS_NS = "http://purl.org/dc/terms/";
private static final String GRAPH_NAME = "myrelations";
@Inject
protected CoreSession session;
@Inject
private RelationManager service;
private CoreGraph graph;
private List<Statement> statements;
private Resource doc1;
private Resource doc2;
private QNameResource isBasedOn;
private QNameResource references;
@Before
public void setUp() throws Exception {
statements = new ArrayList<>();
doc1 = new QNameResourceImpl(RelationConstants.DOCUMENT_NAMESPACE,
session.getRepositoryName() + "/00010000-2c86-46fa-909e-02494bcb0001");
doc2 = new QNameResourceImpl(RelationConstants.DOCUMENT_NAMESPACE,
session.getRepositoryName() + "/00020000-2c86-46fa-909e-02494bcb0002");
isBasedOn = new QNameResourceImpl(DC_TERMS_NS, "IsBasedOn");
references = new QNameResourceImpl(DC_TERMS_NS, "References");
statements.add(new StatementImpl(doc2, isBasedOn, doc1));
statements.add(new StatementImpl(doc1, references,
new ResourceImpl("http://www.wikipedia.com/Enterprise_Content_Management")));
statements.add(new StatementImpl(doc2, references, new LiteralImpl("NXRuntime")));
Collections.sort(statements);
graph = (CoreGraph) service.getGraphByName(GRAPH_NAME);
}
public void useGraphWithSession() throws Exception {
graph = (CoreGraph) service.getGraph(GRAPH_NAME, session);
}
private static String getTestFile() {
String filePath = "test.rdf";
return FileUtils.getResourcePathFromContext(filePath);
}
@Test
public void testSetOptions() {
Map<String, String> options = new HashMap<>();
options.put(CoreGraph.OPTION_DOCTYPE, "Foo");
try {
graph.setOptions(options);
fail("Should have raised IllegalArgumentException");
} catch (IllegalArgumentException e) {
// ok
}
options.put(CoreGraph.OPTION_DOCTYPE, "Relation");
graph.setOptions(options);
}
@Test
public void testAdd() {
assertEquals(Long.valueOf(0), graph.size());
graph.add(statements);
assertEquals(Long.valueOf(3), graph.size());
}
@Test
public void testAddWithKnowPredicateNamespace() {
assertEquals(Long.valueOf(0), graph.size());
Resource src = new ResourceImpl("http://foo.com/bar");
Statement stmt = new StatementImpl(src,
new QNameResourceImpl(RelationConstants.DOCUMENT_NAMESPACE, "startContainer"),
new LiteralImpl("/html[1]/body[1]/p[4], 3"));
graph.add(stmt);
assertEquals(Long.valueOf(1), graph.size());
}
@Test
public void testAddWithSession() throws Exception {
useGraphWithSession();
testAdd();
}
@Test
public void testSubjectResource() {
assertEquals(Long.valueOf(0), graph.size());
Resource src = new ResourceImpl("urn:foo:1234");
Statement st = new StatementImpl(src, isBasedOn, doc1);
graph.add(st);
List<Statement> stmts = graph.getStatements();
assertEquals(1, stmts.size());
assertEquals(st, stmts.get(0));
graph.remove(Collections.singletonList(st));
assertEquals(Long.valueOf(0), graph.size());
}
@Test
public void testBlank() {
assertEquals(Long.valueOf(0), graph.size());
Node src = new BlankImpl();
Node dst = new BlankImpl("123");
Statement st = new StatementImpl(src, isBasedOn, dst);
graph.add(st);
List<Statement> stmts = graph.getStatements();
assertEquals(1, stmts.size());
assertEquals(st, stmts.get(0));
graph.remove(Collections.singletonList(st));
assertEquals(Long.valueOf(0), graph.size());
}
@Test
public void testNamespaces() {
String NS = "http://foo.com/";
// without namespace
Resource src = new ResourceImpl(NS + "bar");
Statement stmt = new StatementImpl(src, isBasedOn, doc1);
graph.add(stmt);
List<Statement> stmts = graph.getStatements();
Statement st = stmts.get(0);
assertEquals(stmt, st);
assertFalse(st.getSubject().isQNameResource());
graph.remove(Collections.singletonList(stmt));
GraphDescriptor desc = new GraphDescriptor();
desc.namespaces = Collections.singletonMap("prfx", NS);
graph.setDescription(desc);
graph.add(stmt);
stmts = graph.getStatements();
st = stmts.get(0);
assertTrue(st.getSubject().isQNameResource());
}
@Test
public void testRemove() {
assertEquals(Long.valueOf(0), graph.size());
graph.add(statements);
assertEquals(Long.valueOf(3), graph.size());
List<Statement> stmts = new ArrayList<>();
stmts.add(new StatementImpl(doc2, references, new LiteralImpl("NXRuntime")));
graph.remove(stmts);
assertEquals(Long.valueOf(2), graph.size());
}
@Test
public void testRemoveWithSession() throws Exception {
useGraphWithSession();
testRemove();
}
@Test
public void testStatementProperties() {
List<Statement> stmts = new ArrayList<>();
Node p;
Calendar cal = Calendar.getInstance();
cal.set(2012, 12 - 1, 21, 1, 2, 3);
cal.set(Calendar.MILLISECOND, 0);
Date date = cal.getTime();
Statement st = new StatementImpl(doc2, isBasedOn, doc1);
st.setProperty(RelationConstants.AUTHOR, new LiteralImpl("bob"));
st.setProperty(RelationConstants.CREATION_DATE, RelationDate.getLiteralDate(date));
st.setProperty(RelationConstants.MODIFICATION_DATE, RelationDate.getLiteralDate(date));
st.setProperty(RelationConstants.COMMENT, new LiteralImpl("hi there"));
graph.add(st);
stmts = graph.getStatements();
assertEquals(1, stmts.size());
st = stmts.get(0);
p = st.getProperty(RelationConstants.AUTHOR);
assertEquals("bob", ((Literal) p).getValue());
// no DublinCoreListener registered, dates are unchanged
p = st.getProperty(RelationConstants.CREATION_DATE);
assertEquals(date.getTime(), RelationDate.getDate((Literal) p).getTime());
p = st.getProperty(RelationConstants.MODIFICATION_DATE);
assertEquals(date.getTime(), RelationDate.getDate((Literal) p).getTime());
p = st.getProperty(RelationConstants.COMMENT);
assertEquals("hi there", ((Literal) p).getValue());
}
@Test
public void testGetStatements() {
List<Statement> stmts = new ArrayList<>();
assertEquals(stmts, graph.getStatements());
graph.add(statements);
stmts = graph.getStatements();
Collections.sort(stmts);
assertEquals(statements, stmts);
}
@Test
public void testGetStatementsPattern() {
List<Statement> expected = new ArrayList<>();
assertEquals(expected, graph.getStatements());
graph.add(statements);
List<Statement> stmts = graph.getStatements(new StatementImpl(null, null, null));
Collections.sort(stmts);
expected = statements;
assertEquals(expected, stmts);
stmts = graph.getStatements(new StatementImpl(doc1, null, null));
Collections.sort(stmts);
expected = new ArrayList<>();
expected.add(new StatementImpl(doc1, references,
new ResourceImpl("http://www.wikipedia.com/Enterprise_Content_Management")));
assertEquals(expected, stmts);
stmts = graph.getStatements(new StatementImpl(null, references, null));
Collections.sort(stmts);
expected = new ArrayList<>();
expected.add(new StatementImpl(doc1, references,
new ResourceImpl("http://www.wikipedia.com/Enterprise_Content_Management")));
expected.add(new StatementImpl(doc2, references, new LiteralImpl("NXRuntime")));
assertEquals(expected, stmts);
stmts = graph.getStatements(new StatementImpl(doc2, null, doc1));
Collections.sort(stmts);
expected = new ArrayList<>();
expected.add(new StatementImpl(doc2, isBasedOn, doc1));
assertEquals(expected, stmts);
// test with unknown nodes
expected = new ArrayList<>();
stmts = graph.getStatements(new StatementImpl(new ResourceImpl("http://subject"),
new ResourceImpl("http://propertty"), new ResourceImpl("http://object")));
assertEquals(expected, stmts);
stmts = graph.getStatements(
new StatementImpl(new ResourceImpl("http://subject"), null, new LiteralImpl("literal")));
assertEquals(expected, stmts);
stmts = graph.getStatements(
new StatementImpl(new ResourceImpl("http://subject"), null, new BlankImpl("blank")));
assertEquals(expected, stmts);
}
@Test
public void testGetStatementsPatternWithSession() throws Exception {
useGraphWithSession();
testGetStatementsPattern();
}
@Test
public void testGetSubjects() {
graph.add(statements);
List<Node> res;
res = graph.getSubjects(references, new ResourceImpl("http://www.wikipedia.com/Enterprise_Content_Management"));
assertEquals(Collections.singletonList(doc1), res);
res = graph.getSubjects(null, doc1);
assertEquals(Collections.singletonList(doc2), res);
Set<Node> docs = new HashSet<>(Arrays.asList(doc1, doc2));
res = graph.getSubjects(references, null);
assertEquals(docs, new HashSet<>(res));
res = graph.getSubjects(null, null);
assertEquals(docs, new HashSet<>(res));
}
@Test
public void testGetPredicates() {
graph.add(statements);
List<Node> res;
res = graph.getPredicates(doc2, doc1);
assertEquals(Collections.singletonList(isBasedOn), res);
res = graph.getPredicates(null, doc1);
assertEquals(Collections.singletonList(isBasedOn), res);
Set<Node> both = new HashSet<>(Arrays.asList(isBasedOn, references));
res = graph.getPredicates(doc2, null);
assertEquals(both, new HashSet<>(res));
res = graph.getPredicates(null, null);
assertEquals(both, new HashSet<>(res));
}
@Test
public void testGetObject() {
graph.add(statements);
List<Node> res;
Literal lit = new LiteralImpl("NXRuntime");
Resource reswiki = new ResourceImpl("http://www.wikipedia.com/Enterprise_Content_Management");
res = graph.getObjects(doc2, isBasedOn);
assertEquals(Collections.singletonList(doc1), res);
res = graph.getObjects(doc2, null);
assertEquals(new HashSet<>(Arrays.asList(doc1, lit)), new HashSet<>(res));
res = graph.getObjects(null, references);
assertEquals(new HashSet<>(Arrays.asList(reswiki, lit)), new HashSet<>(res));
res = graph.getObjects(null, null);
assertEquals(new HashSet<>(Arrays.asList(doc1, reswiki, lit)), new HashSet<>(res));
}
@Test
public void testHasStatement() {
graph.add(statements);
assertFalse(graph.hasStatement(null));
assertTrue(graph.hasStatement(new StatementImpl(doc2, isBasedOn, doc1)));
assertFalse(graph.hasStatement(new StatementImpl(doc2, isBasedOn, doc2)));
assertTrue(graph.hasStatement(new StatementImpl(doc2, isBasedOn, null)));
assertFalse(graph.hasStatement(new StatementImpl(null, null, doc2)));
}
@Test
public void testHasResource() {
graph.add(statements);
assertFalse(graph.hasResource(null));
assertTrue(graph.hasResource(doc1));
assertTrue(graph.hasResource(doc2));
assertTrue(graph.hasResource(isBasedOn));
assertTrue(graph.hasResource(references));
assertFalse(graph.hasResource(new ResourceImpl("http://foo")));
}
@Test
public void testSize() {
assertEquals(Long.valueOf(0), graph.size());
List<Statement> stmts = new ArrayList<>();
stmts.add(new StatementImpl(doc1, isBasedOn, new LiteralImpl("foo")));
graph.add(stmts);
assertEquals(Long.valueOf(1), graph.size());
graph.add(statements);
assertEquals(Long.valueOf(4), graph.size());
}
@Test
public void testClear() {
assertEquals(Long.valueOf(0), graph.size());
graph.add(statements);
assertEquals(Long.valueOf(3), graph.size());
graph.clear();
assertEquals(Long.valueOf(0), graph.size());
}
public void TODOtestQuery() {
graph.add(statements);
String queryString = "SELECT ?subj ?pred ?obj " //
+ "WHERE {" //
+ " ?subj ?pred ?obj " //
+ " }";
QueryResult res = graph.query(queryString, "sparql", null);
assertEquals(3, res.getCount().intValue());
List<String> variableNames = new ArrayList<>();
variableNames.add("subj");
variableNames.add("pred");
variableNames.add("obj");
assertEquals(variableNames, res.getVariableNames());
queryString = "PREFIX dcterms: <http://purl.org/dc/terms/> " + "SELECT ?subj ?obj " + "WHERE {"
+ " ?subj dcterms:References ?obj ." + " }";
res = graph.query(queryString, "sparql", null);
assertEquals(2, res.getCount().intValue());
variableNames.remove("pred");
assertEquals(variableNames, res.getVariableNames());
}
public void TODOtest() {
String queryString = "SELECT ?s ?o WHERE { ?s <http://foo> ?o . }";
/**
* <code>
* SELECT ?s WHERE {?s <http://www.w3.org/2000/10/annotation-ns#body> ?o}
*
* SELECT ?o WHERE {?s <http://www.w3.org/2000/10/annotation-ns#body> ?o}
*
* SELECT ?o WHERE {?s <http://www.w3.org/2000/10/annotation-ns#annotates> ?o}
*
* SELECT ?o WHERE {?s <http://purl.org/dc/elements/1.1/creator> ?o}
*
* SELECT ?s ?p ?o WHERE { ?s ?p ?o . }
*
* SELECT ?s ?p ?o WHERE {
* ?s ?p ?o .
* ?s <http://www.w3.org/2000/10/annotation-ns#annotates> <someuri> .
* }
* </code>
*/
String q = queryString.replace("\n", " ").replace("\r", " ").trim();
Pattern PAT = Pattern.compile("SELECT\\s+" //
+ "(.*)" // group 1
+ "\\s+WHERE\\s*\\{\\s*" //
+ "(.*)" // group 2
+ "\\s*\\}");
Matcher m = PAT.matcher(q);
assertTrue(m.matches());
String g1 = m.group(1);
String g2 = m.group(2);
assertEquals("?s ?o", g1);
String[] vars = g1.split(" ");
for (String var : vars) {
if (!var.startsWith("?") || var.length() == 1) {
throw new IllegalArgumentException("Invalid query variable: " + var + " in query: " + queryString);
}
// String v = var.substring(1);
}
assertEquals("?s <http://foo> ?o . ", g2);
String[] tuples = (g2 + " ").split(" . ");
for (String tuple : tuples) {
tuple = tuple.trim();
if (tuple.isEmpty()) {
continue;
}
assertEquals("?s <http://foo> ?o", tuple);
}
}
public void TODOtestRead() throws Exception {
InputStream in = new FileInputStream(getTestFile());
assertEquals(Long.valueOf(0), graph.size());
graph.read(in, null, null);
assertEquals(Long.valueOf(0), graph.size());
List<Statement> statements = graph.getStatements();
Collections.sort(statements);
// assertSame(statements.size(), this.statements.size());
// for (int i = 0; i < statements.size(); i++) {
// assertEquals(statements.get(i), this.statements.get(i));
// }
assertEquals(statements, this.statements);
}
public void TODOtestReadPath() {
assertEquals(Long.valueOf(0), graph.size());
graph.read(getTestFile(), null, null);
assertFalse(graph.size().intValue() == 0);
List<Statement> statements = graph.getStatements();
Collections.sort(statements);
// assertSame(statements.size(), this.statements.size());
// for (int i = 0; i < statements.size(); i++) {
// assertEquals(statements.get(i), this.statements.get(i));
// }
assertEquals(statements, this.statements);
}
public void TODOtestWrite() throws Exception {
graph.add(statements);
ByteArrayOutputStream out = new ByteArrayOutputStream();
graph.write(out, null, null);
InputStream written = new ByteArrayInputStream(out.toByteArray());
InputStream expected = new FileInputStream(getTestFile());
assertEquals(IOUtils.toString(expected, Charsets.UTF_8).replaceAll("\r?\n", ""),
IOUtils.toString(written, Charsets.UTF_8).replaceAll("\r?\n", ""));
}
public void TODOtestWritePath() throws Exception {
graph.add(statements);
File file = Framework.createTempFile("test", ".rdf");
String path = file.getPath();
graph.write(path, null, null);
InputStream written = new FileInputStream(new File(path));
InputStream expected = new FileInputStream(getTestFile());
String expectedString = IOUtils.toString(expected, Charsets.UTF_8).replaceAll("\r?\n", "");
String writtenString = IOUtils.toString(written, Charsets.UTF_8).replaceAll("\r?\n", "");
assertEquals(expectedString, writtenString);
}
}