blob: cf8db0126523b57a43cec5583d3fb49c5357f569 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018 Aston University.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 3.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-3.0
*
* Contributors:
* Antonio Garcia-Dominguez - initial API and implementation
******************************************************************************/
package org.hawk.timeaware.tests;
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.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.NoSuchElementException;
import org.hawk.backend.tests.BackendTestSuite;
import org.hawk.backend.tests.LogbackOnlyErrorsRule;
import org.hawk.backend.tests.RedirectSystemErrorRule;
import org.hawk.backend.tests.TemporaryDatabaseTest;
import org.hawk.backend.tests.factories.IGraphDatabaseFactory;
import org.hawk.core.graph.IGraphEdge;
import org.hawk.core.graph.IGraphIterable;
import org.hawk.core.graph.IGraphNode;
import org.hawk.core.graph.IGraphTransaction;
import org.hawk.core.graph.timeaware.ITimeAwareGraphDatabase;
import org.hawk.core.graph.timeaware.ITimeAwareGraphNode;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
* Tests for timeaware backends, on the interaction of timepoints with index
* queries and the history of edges and nodes.
*/
@RunWith(Parameterized.class)
public class TimeAwareBackendTest extends TemporaryDatabaseTest {
private ITimeAwareGraphDatabase taDB;
public TimeAwareBackendTest(IGraphDatabaseFactory dbf) {
super(dbf);
}
@Rule
public RedirectSystemErrorRule errRule = new RedirectSystemErrorRule();
@Rule
public LogbackOnlyErrorsRule logRule = new LogbackOnlyErrorsRule();
@Parameters(name="{0}")
public static Object[] params() {
return BackendTestSuite.timeAwareBackends();
}
@Override
public void setup() throws Exception {
super.setup();
taDB = (ITimeAwareGraphDatabase)db;
}
@Test
public void indexQueryEndedNodes() throws Exception {
Object nodeId;
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphNode n1T0 = db.createNode(Collections.singletonMap("x", 1), "test");
db.getMetamodelIndex().add(n1T0, Collections.singletonMap("key", "foo"));
nodeId = n1T0.getId();
tx.success();
}
// same instant, check we have it
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphIterable<? extends IGraphNode> iterable = db.getMetamodelIndex().query("key", "foo");
assertEquals(1, iterable.size());
assertEquals(nodeId, iterable.getSingle().getId());
assertTrue(iterable.iterator().hasNext());
tx.success();
}
// end at instant 1, should still have it from the index
taDB.setTime(1L);
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphNode n1T1 = db.getNodeById(nodeId);
((ITimeAwareGraphNode)n1T1).end();
IGraphIterable<? extends IGraphNode> iterable = db.getMetamodelIndex().query("key", "foo");
assertEquals(1, iterable.size());
assertEquals(nodeId, iterable.getSingle().getId());
assertTrue(iterable.iterator().hasNext());
tx.success();
}
// should not appear from instant 2 onwards
taDB.setTime(2L);
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphIterable<? extends IGraphNode> iterable = db.getMetamodelIndex().query("key", "foo");
assertEquals(0, iterable.size());
assertFalse(iterable.iterator().hasNext());
try {
iterable.getSingle();
fail("Should throw a NoSuchElementException");
} catch (NoSuchElementException ex) {
// pass
}
tx.success();
}
// move to past, should still have it
taDB.setTime(0L);
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphIterable<? extends IGraphNode> iterable = db.getMetamodelIndex().query("key", "foo");
assertEquals(1, iterable.size());
assertEquals(nodeId, iterable.getSingle().getId());
assertTrue(iterable.iterator().hasNext());
tx.success();
}
}
@Test
public void indexQueryReplacedNodes() throws Exception {
Object nodeId;
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphNode n1 = db.createNode(Collections.emptyMap(), "test");
nodeId = n1.getId();
db.getMetamodelIndex().add(n1, Collections.singletonMap("file", "abc.xmi"));
tx.success();
}
taDB.setTime(1L);
try (IGraphTransaction tx = db.beginTransaction()) {
taDB.getNodeById(nodeId).end();
tx.success();
}
taDB.setTime(2L);
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphNode n2 = db.createNode(Collections.emptyMap(), "test");
db.getMetamodelIndex().add(n2, Collections.singletonMap("file", "abc.xmi"));
nodeId = n2.getId();
IGraphIterable<? extends IGraphNode> iterable = db.getMetamodelIndex().query("file", "abc.xmi");
assertEquals(1, iterable.size());
assertEquals(nodeId, iterable.iterator().next().getId());
assertEquals(nodeId, iterable.getSingle().getId());
tx.success();
}
}
@Test
public void nodeEndWithLightEdge() throws Exception {
nodeEndWithEdges(Collections.emptyMap());
}
@Test
public void nodeEndWithHeavyEdge() throws Exception {
nodeEndWithEdges(Collections.singletonMap("container", "true"));
}
private void nodeEndWithEdges(final Map<String, Object> props) throws Exception {
Object id1, id2;
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphNode n1 = db.createNode(null, "example");
IGraphNode n2 = db.createNode(null, "example");
db.createRelationship(n1, n2, "test", props);
id1 = n1.getId();
id2 = n2.getId();
tx.success();
}
taDB.setTime(1L);
try (IGraphTransaction tx = db.beginTransaction()) {
ITimeAwareGraphNode n1 = taDB.getNodeById(id1);
ITimeAwareGraphNode n2 = taDB.getNodeById(id2);
assertTrue(n1.getOutgoing().iterator().hasNext());
assertTrue(n2.getIncoming().iterator().hasNext());
n2.end();
tx.success();
}
try (IGraphTransaction tx = db.beginTransaction()) {
ITimeAwareGraphNode n1 = taDB.getNodeById(id1);
ITimeAwareGraphNode n2 = taDB.getNodeById(id2);
assertTrue(n1.getOutgoing().iterator().hasNext());
assertTrue(n2.getIncoming().iterator().hasNext());
tx.success();
}
taDB.setTime(0L);
try (IGraphTransaction tx = db.beginTransaction()) {
ITimeAwareGraphNode n1 = taDB.getNodeById(id1);
ITimeAwareGraphNode n2 = taDB.getNodeById(id2);
assertTrue(n1.getOutgoing().iterator().hasNext());
assertTrue(n2.getIncoming().iterator().hasNext());
tx.success();
}
taDB.setTime(2L);
try (IGraphTransaction tx = db.beginTransaction()) {
ITimeAwareGraphNode n1 = taDB.getNodeById(id1);
ITimeAwareGraphNode n2 = taDB.getNodeById(id2);
assertFalse(n1.getOutgoing().iterator().hasNext());
assertFalse(n2.isAlive());
tx.success();
}
}
@Test
public void createDeleteHeavyEdgeBeginningOfTime() throws Exception {
taDB.setTime(0L);
createDeleteHeavyEdge();
}
@Test
public void createDeleteHeavyEdgeNonZeroTime() throws Exception {
taDB.setTime(1L);
createDeleteHeavyEdge();
}
@Test
public void nextPrev() throws Exception {
ITimeAwareGraphNode n;
try (IGraphTransaction tx = db.beginTransaction()) {
taDB.setTime(9);
n = taDB.createNode(Collections.singletonMap("x", 1), "example");
tx.success();
}
try (IGraphTransaction tx = db.beginTransaction()) {
n.travelInTime(10).setProperty("x", 3);
tx.success();
}
try (IGraphTransaction tx = db.beginTransaction()) {
n.travelInTime(11).setProperty("x", 5);
tx.success();
}
try (IGraphTransaction tx = db.beginTransaction()) {
assertEquals(Arrays.asList(11L, 10L, 9L), n.getAllInstants());
assertEquals(10, n.travelInTime(9).getNextInstant());
assertEquals(11, n.travelInTime(10).getNextInstant());
assertEquals(ITimeAwareGraphNode.NO_SUCH_INSTANT, n.travelInTime(11).getNextInstant());
assertEquals(ITimeAwareGraphNode.NO_SUCH_INSTANT, n.travelInTime(9).getPreviousInstant());
assertEquals(9, n.travelInTime(10).getPreviousInstant());
assertEquals(10, n.travelInTime(11).getPreviousInstant());
}
}
private void createDeleteHeavyEdge() throws Exception {
Object heavyEdgeId;
try (IGraphTransaction tx = db.beginTransaction()) {
IGraphNode n1 = db.createNode(null, "example");
IGraphNode n2 = db.createNode(null, "example");
IGraphEdge e = db.createRelationship(n1, n2, "example", Collections.singletonMap("key", "value"));
heavyEdgeId = e.getId();
e.delete();
tx.success();
}
try (IGraphTransaction tx = db.beginTransaction()) {
ITimeAwareGraphNode backingNode = taDB.getNodeById(heavyEdgeId);
assertFalse(backingNode.isAlive());
tx.success();
}
}
/* TODO add test cases for derived/indexed properties in combination with time-awareness */
}