Added tests for erroneous arguments/uses of properties and constructor, e.g. outside of tx, or circular refs. Does not include any checks of fields on construction or anything like that.

This commit is contained in:
David Montag
2010-08-10 13:28:52 +02:00
parent 74f956c7dd
commit aae4be683f
2 changed files with 97 additions and 36 deletions

View File

@@ -10,9 +10,12 @@ import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotInTransactionException;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.util.GraphDatabaseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.persistence.graph.GraphEntity;
import org.springframework.persistence.graph.Relationship;
import org.springframework.persistence.support.AbstractTypeAnnotatingMixinFields;
@@ -59,15 +62,19 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
// Create a new node in the Graph if no Node was passed in a constructor
before(NodeBacked entity) : arbitraryUserConstructorOfNodeBackedObject(entity) {
entity.setUnderlyingNode(graphDatabaseService.createNode());
log.info("User-defined constructor called on class " + entity.getClass() + "; created Node [" + entity.getUnderlyingNode() +"]; " +
"Updating metamodel");
// TODO pull naming out into a strategy interface, todo a separate one, or the Entity Instatiator
// graphEntityInstantiator.postEntityCreation(entity);
postEntityCreation(entity);
try {
entity.setUnderlyingNode(graphDatabaseService.createNode());
log.info("User-defined constructor called on class " + entity.getClass() + "; created Node [" + entity.getUnderlyingNode() +"]; " +
"Updating metamodel");
// TODO pull naming out into a strategy interface, todo a separate one, or the Entity Instatiator
// graphEntityInstantiator.postEntityCreation(entity);
postEntityCreation(entity);
} catch(NotInTransactionException e) {
throw new InvalidDataAccessResourceUsageException("Not in a Neo4j transaction.", e);
}
}
public void postEntityCreation(NodeBacked entity) {
private void postEntityCreation(NodeBacked entity) {
Node subReference = Neo4jHelper.findSubreferenceNode(entity.getClass(), graphDatabaseService);
entity.getUnderlyingNode().createRelationshipTo(subReference, Neo4jHelper.INSTANCE_OF_RELATIONSHIP_TYPE);
graphDatabaseUtil.incrementAndGetCounter(subReference, Neo4jHelper.SUBREFERENCE_NODE_COUNTER_KEY);
@@ -145,27 +152,31 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
Object around(NodeBacked entity, Object newVal) : entityFieldSet(entity, newVal) {
FieldSignature fieldSignature=(FieldSignature) thisJoinPoint.getSignature();
Field f = fieldSignature.getField();
// TODO fix arrays
if (f.getType().isPrimitive() || f.getType().equals(String.class)) {
String propName = getNeo4jPropertyName(f);
entity.getUnderlyingNode().setProperty(propName, newVal);
log.info("SET " + f + " -> Neo4J simple node property [" + propName + "] with value=[" + newVal + "]");
return null;
}
// Look for a relationship
if (isNeo4jRelationshipField(f)) {
RelationshipInfo relInfo = RelationshipInfo.forField(f);
graphEntityFieldSet(entity, (NodeBacked) newVal, relInfo);
try {
FieldSignature fieldSignature=(FieldSignature) thisJoinPoint.getSignature();
Field f = fieldSignature.getField();
// TODO fix arrays
if (f.getType().isPrimitive() || f.getType().equals(String.class)) {
String propName = getNeo4jPropertyName(f);
entity.getUnderlyingNode().setProperty(propName, newVal);
log.info("SET " + f + " -> Neo4J simple node property [" + propName + "] with value=[" + newVal + "]");
return null;
}
// Look for a relationship
if (isNeo4jRelationshipField(f)) {
RelationshipInfo relInfo = RelationshipInfo.forField(f);
graphEntityFieldSet(entity, (NodeBacked) newVal, relInfo);
log.info("SET " + f + " -> Neo4J relationship with value=[" + newVal + "]");
return null;
}
else {
log.info("Ignored SET " + f + ": " + f.getType().getName() + " not primitive or GraphEntity");
return proceed(entity, newVal);
log.info("SET " + f + " -> Neo4J relationship with value=[" + newVal + "]");
return null;
}
else {
log.info("Ignored SET " + f + ": " + f.getType().getName() + " not primitive or GraphEntity");
return proceed(entity, newVal);
}
} catch(NotInTransactionException e) {
throw new InvalidDataAccessResourceUsageException("Not in a Neo4j transaction.", e);
}
}
@@ -179,10 +190,13 @@ public aspect Neo4jNodeBacking extends AbstractTypeAnnotatingMixinFields<GraphEn
return;
}
Node targetNode = newVal.getUnderlyingNode();
if (me.equals(targetNode)) {
throw new InvalidDataAccessApiUsageException("Cannot create circular reference.");
}
switch(relationshipInfo.getDirection()) {
case OUTGOING : me.createRelationshipTo(targetNode, relationshipInfo.getType()); break;
case INCOMING : targetNode.createRelationshipTo(me, relationshipInfo.getType()); break;
default : throw new IllegalArgumentException("invalid direction "+relationshipInfo.getDirection());
case OUTGOING : me.createRelationshipTo(targetNode, relationshipInfo.getType()); break;
case INCOMING : targetNode.createRelationshipTo(me, relationshipInfo.getType()); break;
default : throw new IllegalArgumentException("invalid direction "+relationshipInfo.getDirection());
}
}

View File

@@ -10,8 +10,11 @@ import org.junit.runner.RunWith;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.NotInTransactionException;
import org.neo4j.graphdb.Transaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.persistence.graph.Direction;
import org.springframework.persistence.graph.neo4j.NodeBacked;
import org.springframework.persistence.support.EntityInstantiator;
@@ -119,13 +122,57 @@ public class Neo4jGraphPersistenceTest {
Assert.assertEquals(boss, p.getBoss());
}
@Ignore
@Test
@Transactional
public void testBidirectionalRelationshipWithAnnotationOnSet() {
@Test(expected = InvalidDataAccessResourceUsageException.class)
public void testCreateOutsideTransaction() {
Person p = new Person("Michael", 35);
Person friend = new Person("David", 25);
p.setFriend(friend);
}
@Test(expected = InvalidDataAccessResourceUsageException.class)
public void testSetPropertyOutsideTransaction() {
Transaction tx = graphDatabaseService.beginTx();
Person p = null;
try {
p = new Person("Michael", 35);
tx.success();
} finally {
tx.finish();
}
p.setAge(25);
}
@Test(expected = InvalidDataAccessResourceUsageException.class)
public void testCreateRelationshipOutsideTransaction() {
Transaction tx = graphDatabaseService.beginTx();
Person p = null;
Person spouse = null;
try {
p = new Person("Michael", 35);
spouse = new Person("Tina", 36);
tx.success();
} finally {
tx.finish();
}
p.setSpouse(spouse);
}
@Test
public void testGetPropertyOutsideTransaction() {
Transaction tx = graphDatabaseService.beginTx();
Person p = null;
try {
p = new Person("Michael", 35);
tx.success();
} finally {
tx.finish();
}
Assert.assertEquals("Wrong age.", 35, p.getAge());
}
@Test(expected = InvalidDataAccessApiUsageException.class)
@Transactional
public void testCircularRelationship() {
Person p = new Person("Michael", 35);
p.setSpouse(p);
}
@Test