/*******************************************************************************
* Copyright (c) 2014 EURA NOVA.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v2.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* Aldemar Reynaga - initial API and implementation
* Salim Jouili - initial API and implementation
******************************************************************************/
package com.imgraph.tests;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
import junit.framework.Assert;
import org.junit.Test;
import com.steffi.model.EdgeType;
import com.steffi.model.SteffiEdge;
import com.steffi.model.SteffiVertex;
import com.steffi.storage.TransactionRequiredException;
/**
* @author Aldemar Reynaga
* Tests for transactions properties
*/
public class TestTransactions extends BaseLocalTest{
private Object isolationTestLock;
private boolean isolationTestWaiting;
@Test(expected = TransactionRequiredException.class)
public void testNotInitTransException() {
graph.addVertex(2L, null);
}
@Test
public void testAtomicity() {
graph.startTransaction();
SteffiVertex v1 = graph.addVertex(1L, null);
SteffiVertex v103 = graph.getVertex(103);
v1.addEdge(v103, false, "classmate");
v103.putAttribute("weight", 75);
graph.rollback();
assertNull(graph.getVertex(1));
SteffiVertex rv103 = graph.getVertex(103);
assertNull(rv103.getEdge(1, EdgeType.UNDIRECTED, "classmate"));
assertEquals(49, rv103.getAttribute("weight"));
}
@Test
public void testRepeatableRead() {
graph.startTransaction();
graph.getVertex(100);
(new Thread(new RepeatableReadUserThread())).start();
isolationTestLock = new String("Isolation main test lock for repeatable reads");
isolationTestWaiting = true;
try {
synchronized (isolationTestLock) {
while (isolationTestWaiting) {
isolationTestLock.wait();
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
SteffiVertex rv100 = graph.getVertex(100);
for (SteffiEdge edge : rv100.getEdges()) {
if (!isEdgeWith(edge, EdgeType.OUT, "recommends", 103, 100) &&
!isEdgeWith(edge, EdgeType.OUT, "recommends", 104, 100) &&
!isEdgeWith(edge, EdgeType.UNDIRECTED, "classmate", 102, 100))
fail("Edge not valid: " + edge);
}
assertEquals(68, rv100.getAttribute("weight"));
SteffiVertex rv104 = graph.getVertex(104);
rv104.addEdge(graph.getVertex(102), false, "classmate");
graph.commit();
rv100 = graph.getVertex(100);
assertNotNull(rv100.getEdge(103, EdgeType.OUT, "recommends"));
assertNotNull(rv100.getEdge(104, EdgeType.OUT, "recommends"));
assertNotNull(rv100.getEdge(102, EdgeType.UNDIRECTED, "classmate"));
SteffiEdge e100_1 = rv100.getEdge(1, EdgeType.OUT, "recommends");
assertNotNull(e100_1);
assertEquals(2, e100_1.getAttribute("stars"));
assertEquals(100, rv100.getAttribute("weight"));
rv104 = graph.getVertex(104);
assertNotNull(rv104.getEdge(102, EdgeType.UNDIRECTED, "classmate"));
}
@Test
public void testNoDirtyReads() {
graph.startTransaction();
SteffiVertex v1 = graph.addVertex(1L, null);
SteffiVertex v100 = graph.getVertex(100);
SteffiVertex v102 = graph.getVertex(102);
v1.addEdge(v100, false, "classmate");
SteffiEdge e102_1 = v102.addEdge(v1, true, "recommends");
e102_1.putAttribute("stars", 5);
v100.putAttribute("name", "Max");
v102.removeAttribute("weight");
testIsolationChangesApplied(v1, v100, v102);
DirtyReadUserThread userThread = new DirtyReadUserThread();
(new Thread(userThread)).start();
isolationTestLock = new String("Isolation main test lock for dirty reads");
isolationTestWaiting = true;
try {
synchronized (isolationTestLock) {
while (isolationTestWaiting) {
isolationTestLock.wait();
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
graph.commit();
userThread.unlock();
}
private void unlockIsolationTest() {
synchronized (isolationTestLock) {
isolationTestWaiting = false;
isolationTestLock.notifyAll();
}
}
private void testIsolationChangesApplied(SteffiVertex v1, SteffiVertex v100, SteffiVertex v102) {
Assert.assertNotNull(v1);
for (SteffiEdge edge : v1.getEdges()) {
if (isEdgeWith(edge, EdgeType.UNDIRECTED, "classmate", 100, 1)) {
} else if (isEdgeWith(edge, EdgeType.IN, "recommends", 102, 1)) {
Map<String, Object> expectedProp = new HashMap<String, Object>();
expectedProp.put("stars", 5);
checkProperties(edge, expectedProp);
} else {
Assert.fail("Not valid edge: " + edge);
}
}
Assert.assertEquals("Max", v100.getAttribute("name"));
Assert.assertNull(v102.getAttribute("weight"));
}
private class DirtyReadUserThread implements Runnable {
private Object lock;
private boolean waiting;
public DirtyReadUserThread () {
lock = new String("Test lock");
}
public void unlock() {
synchronized (lock) {
waiting = false;
lock.notifyAll();
}
}
@Override
public void run() {
Assert.assertNull(graph.getVertex(1));
SteffiVertex v100 = graph.getVertex(100);
SteffiVertex v102 = graph.getVertex(102);
Assert.assertNull(v100.getEdge(1, EdgeType.UNDIRECTED, "classmate"));
Assert.assertNull(v102.getEdge(1, EdgeType.OUT, "recommends"));
Assert.assertEquals("John", v100.getAttribute("name"));
Assert.assertEquals(77, v102.getAttribute("weight"));
unlockIsolationTest();
waiting = true;
try {
synchronized (lock) {
while (waiting) {
lock.wait();
}
}
Thread.sleep(500);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
testIsolationChangesApplied(graph.getVertex(1), graph.getVertex(100), graph.getVertex(102));
}
}
private class RepeatableReadUserThread implements Runnable {
@Override
public void run() {
graph.startTransaction();
SteffiVertex v1 = graph.addVertex(1L, null);
SteffiVertex v100 = graph.getVertex(100);
SteffiEdge e = v100.addEdge(v1, true, "recommends");
e.putAttribute("stars", 2);
v100.putAttribute("weight", 100);
graph.commit();
unlockIsolationTest();
}
}
}